fbpixel
Créer un script Python sous ROS2

Créer un script Python sous ROS2

Dans ce tutoriel, nous allons voir comment créer et lancer des script Python sous ROS2. Vous pourrez ainsi créer vos propres noeuds et commencer à développer sous ROS.

Créer un espace de travail

Une bonne pratique pour développer sous ROS2 est de créer des workspaces dans lesquels on va installer les paquets désirés, séparés de l’installation principale.

Installation de colcon

sudo apt install python3-colcon-common-extensions

Créer le dossier

mkdir -p ~/tuto_ws/src
cd ~/tuto_ws

Copier ensuite un projet type, comme tutoriel contenant turtlesim

git clone https://github.com/ros/ros_tutorials.git -b iron

Puis construisez le projet à l’aide de la commande

colcon build

Pour charger votre workspace dans un nouveau terminal

source /opt/ros/iron/setup.bash
cd ~/ros2_ws
source install/local_setup.bash

N.B.: vous pouvez mettre les commandes suivantes dans un fichier ros_profile pour le source en une seule commande “source ros_profile”

Créer un Package python

ROS2 offre un outil simple pour créer l’architecture de fichiers d’un paquets Python ou C++. Vous devez alors spécifier au moins le nom du paquet (my_paquet). Il est possible également de donner le nom du nœud.

Dans le répertoire ~/ros2_sw/src, entrez la commande suivante

ros2 pkg create --build-type ament_python --license Apache-2.0 --node-name my_node my_package --license Apache-2.0

le script python se trouve alors dans le répertoire ~/ros2_ws/src/my_package/my_package

Une fois le paquet créé, vous pouvez ajouter autant de nœud que vous le souhaitez dans ce dossier.

Il faudra penser à mettre à jour les fichiers setup.py et package.xml avec les dépendances et points d’entrée

Installer les dépendances

Avant de compiler le projet, il est conseillé de résoudre les dépendances.

rosdep install -i --from-path src --rosdistro iron -y

Compiler le projet

Il est possible de compiler le projet entier ou de sélectionner un paquet en particulier

colcon build --packages_select my_package --symlink-install

N.B.: symlink-install permet de ne pas recompiler à chaque changement du script Python

Lancer le nœud

Une fois le paquet compilé, vous pouvez lancer le nœud à partir de la commande

ros2 run my_package my_node

Le code de base lors de la création d’un nœud

def main():
    print('Hi from my_package.')

if __name__ == '__main__':
    main()

Au lancement ce code affichera simplement le text du print

Création d’un Publisher et d’un Subscriber pour Turtlesim

Nous allons voir dans cet exemple, comment créer un paquet avec deux nœuds, l’un venant contrôler la tortue, l’autre, venant lire la position.

Création du paquet

ros2 pkg create --build-type ament_python --license Apache-2.0 --node-name projects control_turtle --license Apache-2.0

Voici l’architecture de fichiers désiré

.
├── LICENSE
├── package.xml
├── projects
│   ├── control_turtle.py
│   └── read_turtle.py
├── setup.cfg
└── setup.py

Ajouter les scripts Python

  • Publisher control_turtle.py

On importe le type de message à publier Twist pour le contrôle de la vitesse de la tortue

On se connecte au topic en précisant le nom (‘/turtle1/cmd_vel’) et le type de donnée (Twist)

On crée un timer qui nous permettra de publier régulièrement sur le topic (create_timer)

Enfin on publie la vitesse lineaire et angulaire

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  control_turtle.py


import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist

import os

# Node should have the same name as the node file
nodename= os.path.splitext(os.path.basename(__file__))[0]

class TurtleController(Node):

	def __init__(self):
		super().__init__(nodename)
		self.get_logger().info(nodename+" started")
		self.publisher_ = self.create_publisher(
			Twist,
			'/turtle1/cmd_vel',
			10)
		timer_period = 0.5  # seconds
		self.timer = self.create_timer(timer_period, self.timer_callback)
		self.i = 0

	def timer_callback(self):
		#msg = String()
		#msg.data = 'Hello World: %d' % self.i
		msg = Twist()
		msg.linear.x = 1.0
		msg.angular.z = 0.5
		self.publisher_.publish(msg)
		self.get_logger().info('Publishing: "%s"' % msg)
		self.i += 1


def main(args=None):
	rclpy.init(args=args)

	turtle_controller = TurtleController()
	try:
		rclpy.spin(turtle_controller)
		turtle_controller.destroy_node()
		rclpy.shutdown()
	except:
		turtle_controller.get_logger().info(nodename+" stopped")


if __name__ == '__main__':
	main()

  • Subscriber read_turtle.py

On importe le type de message à publier Pose

On se connecte au topic en précisant le nom (‘/turtle1/pose’) et le type de donnée (Pose)

On écrit la fonction d’écoute qui s’exécute lorsqu’une une nouvelle donnée est disponible sur le topic

On crée un timer qui nous permettra d’afficher les valeurs à la féquence désirée

Enfin on publie la vitesse lineaire et angulaire

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  control_turtle.py


import rclpy #rospy
from rclpy.node import Node
from turtlesim.msg import Pose


import os

# Node should have the same name as the node file
nodename= os.path.splitext(os.path.basename(__file__))[0]

class TurtleReader(Node):

	def __init__(self):
		super().__init__(nodename)
		self.get_logger().info(nodename+" started")
		self.subscription = self.create_subscription(
			Pose,
			'/turtle1/pose',
			self.listener_callback,
			10)
		self.subscription  # prevent unused variable warning
		self.timer = self.create_timer(2, self.timer_callback)
		self.msg = None
		
	def listener_callback(self, msg):
		self.msg = msg
		
	def timer_callback(self):
		self.get_logger().info("I read %s" % self.msg )
		


def main(args=None):
	rclpy.init(args=args)

	turtle_reader = TurtleReader()
	try:
		rclpy.spin(turtle_reader)
		turtle_reader.destroy_node()
		rclpy.shutdown()
	except:
		turtle_reader.get_logger().info(nodename+" stopped")





if __name__ == '__main__':
	main()

Modifier le fichier setup.py

Dans les points d’entrée du fichier setup.py, vous devez spécifier les noms des noeuds ainsi que la fonction à lancer (main)

entry_points={
        'console_scripts': [
                'control_turtle = projects.control_turtle:main',
                'read_turtle = projects.read_turtle:main',
        ],
},

Compiler le paquet

colcon build --packages_select projects --symlink-install

Lancer les noeuds

Pour lancer un noeud dans un terminal, vous devez sourcer le projet

source /opt/ros/iron/setup.bash
cd ~/ros2_ws
source install/local_setup.bash

Dans trois terminaux différents, lancez les commandes suivantes

ros2 run turtlesim turtlesim_node #terminal1
ros2 run projects read_turtle #terminal2
ros2 run projects control_turtle #terminal3

Résultat

Vous pouvez voir la tortue décrire la forme d’un cercle et la position évoluer dans la fentre du subscriber

Lancer un noeud avec des arguments

Il est possible de configurer les noeuds lors de leur exécution. Dans cet exemple, nous allons définir des paramètre d’entrée pour la vitesse linéaire et angulaire. Nous allons donc modifier le code du Publieur ci-dessus

Dans l’initialisation du noeud, nous déclarons les paramètres avec les valeurs par défaut

    self.declare_parameter('x', 1.0)
    self.declare_parameter('z', 0.5)

Nous pouvons ensuite récupérer la valeur de ces paramètres pour les stocker dans des variables que nous utilisons dans la fonction callback

    self.linx = self.get_parameter('linx').get_parameter_value().double_value
    self.angz = self.get_parameter('angz').get_parameter_value().double_value

Vous pouvez désormais lancer un noeud avec et sans paramètre

ros2 run projects circle_turtle #default param
ros2 run projects circle_turtle --ros-args -p linx:=0.5 -p angz:=1.0

Code complet

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  control_turtle.py
import rclpy #rospy
from rclpy.node import Node
from std_msgs.msg import String

from turtlesim.msg import Pose
from geometry_msgs.msg import Twist

import os

nodename= os.path.splitext(os.path.basename(__file__))[0]

class TurtleController(Node):

	def __init__(self):
		super().__init__(nodename)
		self.get_logger().info(nodename+" started")
		self.publisher_ = self.create_publisher(
			Twist,
			'/turtle1/cmd_vel',
			10)
			
		self.declare_parameter('linx', 1.0)
		self.declare_parameter('angz', 0.5)
		self.linx = self.get_parameter('linx').get_parameter_value().double_value
		self.angz = self.get_parameter('angz').get_parameter_value().double_value
			
		timer_period = 0.5  # seconds
		self.timer = self.create_timer(timer_period, self.timer_callback)
		self.i = 0

	def timer_callback(self):
		#msg = String()
		#msg.data = 'Hello World: %d' % self.i
		msg = Twist()
		msg.linear.x = self.linx
		msg.angular.z = self.angz
		self.publisher_.publish(msg)
		self.get_logger().info('Publishing: "%s"' % msg)
		self.i += 1


def main(args=None):
	#os.system('ros2 service call /reset std_srvs/srv/Empty') #reset pos
	rclpy.init(args=args)

	turtle_controller = TurtleController()
	try:
		rclpy.spin(turtle_controller)
		turtle_controller.destroy_node()
		rclpy.shutdown()
	except:
		turtle_controller.get_logger().info(nodename+" stopped")


if __name__ == '__main__':
	main()

Ouvrir les différents terminaux avec un script

Pour gagner du temps lors de votre développement, vous pouvez ouvrir les terminaux et lancer les noeuds à partir d’un seul script bash

#open terminal and run turtlesim
gnome-terminal -- $SHELL -c "source ros_profile && ros2 run turtlesim turtlesim_node;exec $SHELL"
gnome-terminal -- $SHELL -c "source ros_profile && ros2 run projects control_turtle;exec $SHELL"

Troubleshoot

  • SetupTools deprecation

Vérifier la version setuptools

python3
import setuptools
setuptools.__version__

‘59.6.0’

Installer pip

sudo apt install python3-pip

puis installer la version 58.2.0 de setuptools

python3 -m pip install setuptools==58.2.0

Sources

Installer ROS2 sur Raspberry Pi

Installer ROS2 sur Raspberry Pi

Dans ce tutoriel, nous allons voir comment installer ROS2 sur une machine Linux et notamment un Raspberry Pi 4 avec une distribution Ubuntu. ROS2 est un framework intéressant à abordé lorsqu’on travaille sur des systèmes embarqués comme les robots.

Matériel

  • Ordinateur avec accès internet
  • Carte SD 32Go
  • Raspberry Pi+écran HDMI+clavier/souris

Ce tutoriel peut être suivit pour d’autres machines Linux

Téléchargement Ubuntu et configuration de la carte SD

Nous allons voir comment configurer la carte SD pour installer ROS2 (Iron Irwini) sur Raspberry Pi. Cette version de ROS2 est compatible avec Ubuntu Jammy.

Pour cela télécharger l’image d’Ubuntu (Jammy jellyfish) ou sélectionnez l’OS sous Raspberry Pi Imager > General OS > Ubuntu > Ubuntu Desktop 22.04.3 LTS (64bits)

N.B.: vous pouvez retrouver la compatibilité des versions entre ROS et OS et les noms des versions Ubuntu pour vérifier que vous installez les bonnes versions. Sélectionnez la version 64bits pour un meilleur support (tier1)

Installer l’image de l’OS à l’aide de Raspberry Pi Imager sur la carte SD

Une fois l’image écrite sur la carte SD vous pouvez l’insérer dans le Raspberry Pi puis le mettre sous tension.

Vous pouvez ensuite suivre les instructions de configuration sur l’écran du Raspberry Pi.

Configurer la connexion à distance

Vous pouvez, si vous le désirez, configurer la connexion à distance sur Raspberry Pi. Cette étape est optionnelle mais peut vous simplifier la vie lorsque vous développerez sur ROS2 sous Raspberry Pi.

N.B.: sur Ubuntu, pour vous connecter à distance sans moniteur, vous devez modifier le fichier /boot/firmware/config.txt

#dtoverlay=vc4-kms-v3d
hdmi_force_hotplug=1
hdmi_group=1
hdmi_mode=16

Installation de ROS2

Pour l’installation de ROS2, vous devez tout d’abord vérifier que le téléchargement de dépôt Universe est activé. Dans Software & Updates > Ubuntu Software

Ajouter ensuite la clé GPG pour ROS2

sudo apt install curl -y
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg

Puis ajouter le dépôt à la liste des sources (/etc/source.list.d)

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

Pour le développement, vous pouvez installer les outils de dev

sudo apt update && sudo apt install ros-dev-tools

Vous pouvez enfin installer ROS2 en fonction de la version choisi (desktop ou base)

sudo apt install ros-iron-desktop

ou

sudo apt install ros-iron-ros-base

Pour désinstaller ROS2

Pour la désinstallation, il faut supprimer le paquet ainsi que le dépôt

sudo apt remove ~nros-iron-* && sudo apt autoremove
sudo rm /etc/apt/sources.list.d/ros2.list
sudo apt update

Premier pas avec ROS2

Une fois ROS2 installé, vous pouvez charger l’environnement avec

source /opt/ros/iron/setup.bash

Vous pouvez tester l’installation à l’aide de l’exemple talker/listener

Dans un terminal, lancer le talker

source /opt/ros/iron/setup.bash
ros2 run demo_nodes_cpp talker

Dans un second terminal lancer le listener

source /opt/ros/iron/setup.bash
ros2 run demo_nodes_py listener

Pour vérifier la liste des variables d’environnement

printenv | grep -i ROS

Pour avoir la liste des objets en exécution, vous pouvez utiliser les commandes

ros2 node list
ros2 topic list
ros2 service list
ros2 action list

Installation de TurtleSim

Un bel outil pour apprendre et bien comprendre le fonctionnement de ROS2 est TurtleSim

Vérifier son installation à l’aide de la commande

ros2 pkg executables turtlesim

Si ce n’est pas le cas, vous pouvez installer turtlesim à l’aide de la commande

sudo apt install ros-iron-turtlesim

Dans un terminal lancer turtle sim

ros2 run turtlesim turtlesim_node

Dans une autre terminal, lancer le contrôle par clavier

ros2 run turtlesim turtle_teleop_key

Pour observer ce qu’il se passe, dans un troisième terminal, espionner le topic avec la commande

ros2 topic echo /turtle1/pose

Vous pouvez retrouver la liste des topic disponible à l’aide de la commande

ros2 topic list

Application

Sources