fbpixel
Etiquetas: , , ,
0
(0)

Neste tutorial, veremos como criar e executar scripts Python no ROS2. Isto permitir-lhe-á criar os seus próprios nós e começar a desenvolver com o ROS.

Criar um espaço de trabalho

Uma boa prática para desenvolver sob o ROS2 é criar espaços de trabalho nos quais instalar os pacotes desejados, separados da instalação principal.

Instalação do Colcon

sudo apt install python3-colcon-common-extensions

Criar pasta

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

Em seguida, copie um projeto de exemplo, como o tutorial que contém o turtlesim

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

Em seguida, construa o projeto utilizando o comando

colcon build

Para carregar o seu espaço de trabalho num novo terminal

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

N.B.: pode colocar os seguintes comandos num ros_profile para a fonte num único comando “source ros_profile”

Criar um pacote python

O ROS2 oferece uma ferramenta simples para criar a arquitetura de arquivos de um pacote Python ou C++. É necessário especificar pelo menos o nome do pacote (my_package). Também é possível dar o nome do nó.

No diretório ~/ros2_sw/src, introduza o seguinte comando

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

o script python está agora no diretório ~/ros2_ws/src/my_package/my_package

Uma vez criado o pacote, pode adicionar tantos nós quantos quiser a esta pasta.

Terá de atualizar os ficheiros setup.py e package.xml com as dependências e os pontos de entrada

Instalação de dependências

Antes de compilar o projeto, é aconselhável resolver as dependências.

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

Compilar o projeto

É possível compilar todo o projeto ou selecionar um pacote específico

colcon build --packages_select my_package --symlink-install

N.B.: symlink-install significa que não tens de recompilar sempre que alteras o script Python.

Lançar o nó

Depois de o pacote ter sido compilado, pode iniciar o nó com o comando

ros2 run my_package my_node

O código básico para criar um nó

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

if __name__ == '__main__':
    main()

Quando iniciado, este código apresenta simplesmente o texto da impressão

Criar um editor e um subscritor para o Turtlesim

Neste exemplo, veremos como criar um pacote com dois nós, um controlando a tartaruga e o outro lendo a posição.

Criação de pacotes

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

Aqui está o ficheiro de arquitetura desejado

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

Adicionar scripts Python

  • Editor controlo_tartaruga.py

Importamos o tipo de mensagem a publicar Torcer para controlar a velocidade da tartaruga

Ligamo-nos ao tópico especificando o nome (‘/turtle1/cmd_vel’) e o tipo de dados (Twist)

Criamos um temporizador que nos permitirá publicar regularmente sobre o tema (create_timer)

Finalmente, publicamos a linha e a velocidade angular

#!/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()
  • Assinante read_turtle.py

Importar o tipo de mensagem a publicar Pose

Ligamo-nos ao tópico especificando o nome (‘/turtle1/pose’) e o tipo de dados (Pose)

Escrevemos a função de escuta que é executada quando estão disponíveis novos dados sobre o tema

Criamos um temporizador que nos permitirá apresentar os valores com a frequência pretendida

Finalmente, publicamos a linha e a velocidade angular

#!/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()

Modificar setup.py

Nos pontos de entrada do ficheiro setup.py, é necessário especificar os nomes dos nós e a função a executar (main)

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

Compilação do pacote

colcon build --packages_select projects --symlink-install

Lançamento de nós

Para lançar um nó num terminal, é necessário obter a fonte do projeto

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

Em três terminais diferentes, execute os seguintes comandos

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

Resultados

Vê-se que a tartaruga descreve a forma de um círculo e a mudança de posição no centro do assinante.

Lançar um nó com argumentos

Os nós podem ser configurados em tempo de execução. Neste exemplo, vamos definir parâmetros de entrada para a velocidade linear e angular. Por isso, vamos modificar o código no editor acima

Na inicialização do nó, declaramos os parâmetros com os valores por defeito

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

Podemos então obter o valor destes parâmetros e armazená-los em variáveis que utilizamos na função de retorno de chamada

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

Agora é possível iniciar um nó com e sem o

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

Código completo

#!/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()

Abrir os vários terminais com um script

Para poupar tempo durante o desenvolvimento, pode abrir terminais e lançar nós a partir de um único 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"

Resolução de problemas

  • Descontinuação do SetupTools

Verificar a versão do setuptools

python3
import setuptools
setuptools.__version__

‘59.6.0’

Instalar o pip

sudo apt install python3-pip

depois instale a versão 58.2.0 do setuptools

python3 -m pip install setuptools==58.2.0

Fontes

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.

As you found this post useful...

Follow us on social media!

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?