1.1.1. Installation
La version de ROS utilisée est ROS2 Jazzy prévu pour un fonctionnement sur Ubuntu 24.04. Une grande partie du code utilise et est inspiré par Nav2.
Un guide pest disponible dans la documentation officielle de ROS2 Jazzy pour l’installation.
Une fois ROS installé, le dépôt GitHub doit être cloné si cela n’est pas déjà fait.
git clone https://github.com/Hermine-HRC/cdfr.git
Ensuite, se rendre dans le dossier robot/ros_ws/. Le fichier README.md contient les instructions
pour installer les dépendances.
Le fichier contient les packages ROS à installer, la version de Gazebo à utiliser pour les simulations ainsi que divers utilitaires nécessaires au développement.
La compilation du code peut être effectuée avec la commande suivante :
colcon build
Avertissement
La compilation peut prendre plusieurs minutes.
Il faut sourcer le workspace pour utiliser les packages créés à l’aide de la commande suivante :
source install/setup.bash
1.1.2. Fonctionnement code
Plusieurs packages ont été créés, chacun ayant un rôle différent, afin de répondre à différents besoins.
Leur usage est détaillé respectivement dans les fichiers README.md du dossier correspondant.
Certains packages contiennent du code C++ et Python. Le code C++ est contenu dans les dossiers
src/ et include/. Le code Python quant à lui est contenu dans le dossier du même nom que le package.
Important
Dans les packages cmake (avec un fichier CMakeLists.txt), les exécutables Python (fichiers
avec un main) doivent avoir un shebang #!/usr/bin/env python3 en haut du fichier.
Le package bringup contient les fichiers de launch regroupant tous les packages.
Astuce
Pour avoir une coloration des logs, exécuter export RCUTILS_COLORIZED_OUTPUT=1 dans le terminal avant de
lancer le launch.
Les nœuds peuvent tous être configurés via un fichier de configuration au format YAML. Par conséquent, il est préférable d’utiliser un fichier de configuration pour les paramètres de nœuds plutôt que mettre ces paramètres en brut dans le code.
1.1.2.1. Les fichiers .erb
Ces fichiers sont des templates ERB. Ils sont utilisés pour générer les fichiers de données à partir de code en Ruby.
Ils permettent notamment de réaliser des boucles afin d’éviter de dupliquer des informations.
Ils sont convertis en fichiers de données à la compilation suivant les règles données dans le ficher
CMakeLists.txt.
1.1.2.2. Herminebot ou HRC
Tous les packages sont préfixés herminebot_ ou hrc_.
Ceux qui commencent par hrc_ sont des packages qui ont pour vocation d’être utilisés en tant que bibliothèque
alors que ceux qui commencent par herminebot_ sont des packages qui ont pour vocation d’être utilisés
pour le fonctionnement de l’herminebot.
1.1.3. Fonctionnement tests
Les tests permettent de vérifier que le code est correct et qu’il respecte les conventions de programmation.
Ils sont contenus dans le dossier test/ de chaque package.
Les frameworks utilisés sont :
ament_cmake_pytestpour le code Pythonament_cmake_gtestpour le code C++
Des linters, logiciels qui vérifient la forme du code, sont utilisés afin de vérifier que le code respecte les conventions de programmation :
flake8etpep257pour le code Pythonuncrustifypour le code C++
Les règles sont détaillées dans la partie Conventions de programmation.
1.1.3.1. Exécuter les tests
Pour exécuter les tests, il faut d’abord compiler le code puis exécuter les tests.
colcon build
colcon test
Les tests ne mettent que quelques secondes à s’exécuter.
Les détails des tests peuvent être affichés avec la commande suivante :
colcon test-result --all --verbose
Note
Pour toutes les erreurs de linter, il suffit de corriger de la façon qui est proposée (sauf cas exceptionnel).
1.1.3.2. Exécution sur GitHub
Les tests sont exécutés sur GitHub, afin de vérifier que le code est correct et qu’il respecte les conventions de
programmation, à chaque push sur la branche master ou dans une pull request.
Avertissement
Il faut plus de 10 minutes pour exécuter les tests sur GitHub car toute l’installation puis la compilation sont réalisées.
Si les tests échouent, il faut vérifier en local si ça échoue aussi et la cas échéant corriger le code. Si en local les tests passent, c’est parce que les tests échouent parfois de manière intermittente. Dans ce cas, il faut relancer les tests.
Une fois que les tests sont passés, une couverture de code est générée. Le rapport est accessible sur le site
codecov ou en cliquant sur le badge codecov
dans le README.
1.1.3.3. Tests à ajouter
Autant que possible, il faut ajouter des tests afin de vérifier que le code fonctionne correctement.
Soit avec le framework gtest pour les tests C++ ou avec pytest pour les tests Python.
À ça s’ajoute aussi des tests pour vérifier que le code est conforme aux conventions de programmation.
1.1.3.3.1. C++
test_foo.cpp
#include <gtest/gtest.h>
#include "foo.hpp"
class Tester : public ::testing::Test
{
public:
Tester() {foo_ = std::make_shared<Foo>();}
protected:
std::shared_ptr<Foo> foo_;
};
TEST(Tester, test_foo)
{
ASSERT_EQ(foo_->baz(), 1);
}
int main(int argc, char** argv)
{
// Initialize the system
testing::InitGoogleTest(&argc, argv);
rclcpp::init(argc, argv);
// Actual testing
bool test_result = RUN_ALL_TESTS();
// Shutdown
rclcpp::shutdown();
return test_result;
}
test_uncrustify.py
from ament_index_python.packages import get_package_share_directory
from ament_uncrustify.main import main
import os
import pytest
@pytest.mark.linter
def test_uncrustify():
cfg_file = os.path.join(get_package_share_directory("herminebot_bringup"), "config", "ament_code_style.cfg")
rc = main(argv=[f"-c{cfg_file}"])
assert rc == 0, "Found uncrustify errors"
CMakeLists.txt
ament_add_gtest(test_foo test_foo.cpp)
target_link_libraries(test_foo
foo_lib
)
set(python_tests
test_uncrustify.py
)
foreach(python_test ${python_tests})
string(REPLACE "/" "_" python_test_name ${python_test})
ament_add_pytest_test(${python_test_name} ${python_test}
APPEND_ENV PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}
TIMEOUT 60
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
endforeach()
1.1.3.3.2. Python
test_foo.py
import foo
import pytest
import rclpy
def test_demo():
rclpy.init()
try:
node = foo.Foo()
assert node.baz() == 1
finally:
rclpy.shutdown()
if __name__ == '__main__':
pytest.main(['-v'])
test_flake8.py
from ament_flake8.main import main_with_errors
import pytest
@pytest.mark.flake8
@pytest.mark.linter
def test_flake8():
rc, errors = main_with_errors(argv=['--linelength=120', '--exclude=$pkg_name$/__init__.py'])
assert rc == 0, \
'Found %d code style errors / warnings:\n' % len(errors) + \
'\n'.join(errors)
test_pep257.py
from ament_pep257.main import main
import pytest
@pytest.mark.linter
@pytest.mark.pep257
def test_pep257():
rc = main(argv=['.', 'test'])
assert rc == 0, 'Found code style errors / warnings'
Important
Si le code se situe dans un package cmake, il faut modifier le fichier CMakeLists.txt pour ajouter les tests.
set(python_tests
test_foo.py
test_flake8.py
test_pep257.py
)
foreach(python_test ${python_tests})
ament_add_pytest_test(${python_test} ${python_test}
APPEND_ENV PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}
TIMEOUT 60
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
endforeach()
1.1.5. Écrire de nouveaux messages
Les messages sont des structures de données qui sont utilisés pour communiquer entre les nœuds. Ils sont de 3 types :
actions
services
messages
Pour plus d’informations, se rendre dans la documentation officielle de ROS2 qui explique le concept des interfaces.
Dans le projet, les messages créés le sont dans le package hrc_interfaces.
Pour créer un nouveau message, se référer au tutoriel sur les messages de ROS2.
1.1.6. Fourre tout
1.1.6.1. Débugger un nœud C++
Pour débugger un nœud C++ avec le débugger de VSCode, voir les explications de JADC362.
Avertissement
Certains packages ne peuvent pas être compilés avec l’argument --symlink-install.
1.1.6.2. Faire une appel de service depuis un nœud qui spin déjà
Pour faire une appel de service depuis un nœud qui spin déjà, voir la demo de ijnek.
Le fait d’envoyer une requête puis de gérer le résultat dans une callback permet au nœud de réaliser l’appel de service sans avoir besoin de spin avec la fonction spin_until_future_complete.