Criação de Serviços Personalizados no ROS 2 e Controle de Movimento do Robô em Python – Portuguese ROS Tutorial

Written by Anderson Nardin

22/08/2024

This tutorial is created by Robotics Ambassador – Anderson

Robotics Ambassador: theconstruct.ai/robotics-ambassador/

 

O que nós vamos aprender:

  1. Criação de um serviço personalizado no ROS2.
  2. Configuração do ambiente ROS2 para garantir que todas as dependências estão corretamente instaladas e atualizadas.
  3. Criação de um pacote ROS2 incluindo a estrutura de diretórios e os arquivos necessários para o projeto.
  4. Implementação de um servidor e cliente de serviço para controle de movimento do robô.
  5. Criação e edição de arquivos de lançamento (launch files) no ROS2.
  6. Compilação e execução dos pacotes ROS2.
  7. Teste e verificação do serviço para controlar o movimento do robô em diferentes direções.

 

Lista de recursos usados neste post:

  1. Use este rosject: https://app.theconstruct.ai/l/639df241/
  2. The Construct: https://app.theconstructsim.com/
  3. ROS Courses: ROS Basics in 5 Days (C++) https://app.theconstructsim.com/courses/132

 

Panorama

Neste tutorial, vamos aprender a criar serviços personalizados no ROS2 e desenvolver um pacote de controle de movimento para um robô. Vamos passar pelos passos de criação e configuração de serviços, desenvolvimento de um pacote de movimento, implementação do servidor e cliente de serviço, e a criação de arquivos de lançamento. Este tutorial é ideal para quem deseja aprimorar suas habilidades em ROS2 e programação robótica.

 

Abrindo o rosject

Clique no link abaixo para ter acesso ao rosject deste tutorial. Em seguida, clique no botão “RUN”.

https://app.theconstruct.ai/l/639df241/

<figure1>

Criando o Serviço Personalizado

Criação do Pacote de Interfaces Personalizadas

Primeiro, vamos criar um pacote de interfaces personalizadas que conterá nosso serviço. Este pacote será responsável por definir e gerenciar a interface do serviço que iremos usar para controlar o robô.

Copie este bloco de comandos no primeiro terminal:

cd ~/ros2_ws/src
ros2 pkg create --build-type ament_cmake custom_interfaces --dependencies rclcpp std_msgs

Esses comandos criam um novo pacote chamado custom_interfaces com as dependências rclcpp e std_msgs.

Definição do Serviço

Em seguida, vamos definir o serviço que será utilizado para controlar o robô. Para isso, crie uma pasta chamada srv dentro do pacote custom_interfaces e um arquivo Move.srv. Use os comandos:

cd ~/ros2_ws/src/custom_interfaces
mkdir srv
cd srv
touch Move.srv

Edite o arquivo Move.srv com o seguinte conteúdo:

string direction               # Direção para girar (direita ou esquerda)
float64 velocity               # Velocidade angular (em rad/s) ou linear (em m/s)
int32 time                     # Duração do giro (em segundos)
---
bool success                   # O comando foi bem-sucedido?

Esse arquivo define a estrutura do serviço. Ele recebe a direção, velocidade e tempo como entrada, e retorna um booleano indicando se a operação foi bem-sucedida.

Atualizando os Arquivos CMakeLists.txt e package.xml

Agora, precisamos configurar os arquivos CMakeLists.txt e package.xml para que o ROS2 possa construir e utilizar nosso serviço.

No arquivo CMakeLists.txt, adicione:

find_package(rosidl_default_generators REQUIRED)
.
.
.
rosidl_generate_interfaces(${PROJECT_NAME}
"srv/Move.srv"
)

Essas linhas garantem que o gerador de interfaces do ROS2 processe nosso arquivo Move.srv.

No arquivo package.xml, adicione:

<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>

Essas dependências são necessárias para a construção e execução do nosso serviço.

Compilação e Verificação

Agora, compile o pacote e verifique se o serviço foi criado corretamente.

cd ~/ros2_ws
colcon build --packages-select custom_interfaces
source ~/ros2_ws/install/setup.bash

Para verificar se a mensagem de serviço foi criada:

ros2 interface show custom_interfaces/srv/Move

Criando o Pacote de Movimento

Vamos criar um pacote que implementará a lógica de movimento do robô, incluindo um servidor e um cliente de serviço.

cd ~/ros2_ws/src
ros2 pkg create --build-type ament_python movement_pkg --dependencies rclpy custom_interfaces std_msgs geometry_msgs sensor_msgs

Este comando cria um pacote chamado movement_pkg com as dependências necessárias.

Crie os arquivos necessários com os comandos:
cd ~/ros2_ws/src/movement_pkg/movement_pkg
touch movement_server.py movement_client.py

Implementação do Servidor de Serviço

Crie e edite o arquivo movement_server.py com o seguinte conteúdo:


from geometry_msgs.msg import Twist
from custom_interfaces.srv import Move
import rclpy
from rclpy.node import Node
import time

class Service(Node):
    def __init__(self):
        super().__init__('move_server')
        self.srv = self.create_service(Move, 'move', self.custom_service_callback)
        self.publisher_ = self.create_publisher(Twist, 'cmd_vel', 10)

    def custom_service_callback(self, request, response):
        msg = Twist()
        if request.direction == "right":
            msg.angular.z = -request.velocity
        elif request.direction == "left":
            msg.angular.z = request.velocity
        elif request.direction == "forward":
            msg.linear.x = request.velocity
        elif request.direction == "backward":
            msg.linear.x = -request.velocity
        elif request.direction == "stop":
            msg.linear.x = 0.0
            msg.angular.z = 0.0
            self.publisher_.publish(msg)
            response.success = True
            return response
        else:
            response.success = False
            return response

        self.publisher_.publish(msg)
        time.sleep(request.time)
        msg.linear.x = 0.0
        msg.angular.z = 0.0
        self.publisher_.publish(msg)
        response.success = True
        return response

def main(args=None):
    rclpy.init(args=args)
    service = Service()
    rclpy.spin(service)
    rclpy.shutdown()

if __name__ == '__main__':
    main()

Explicação do código:

  • Importamos as bibliotecas necessárias.
  • Definimos a classe Service, que herda de Node.
  • No método __init__, criamos o serviço e o publicador.
  • O método custom_service_callback define a lógica de controle do robô com base nos parâmetros recebidos.
  • No final, iniciamos e rodamos o nó ROS2.

Implementação do Cliente de Serviço

Crie e edite o arquivo movement_client.py com o seguinte conteúdo:


from custom_interfaces.srv import Move
import rclpy
from rclpy.node import Node
import sys

class ClientAsync(Node):
    def __init__(self):
        super().__init__('move_client')
        self.client = self.create_client(Move, 'move')
        while not self.client.wait_for_service(timeout_sec=1.0):
            self.get_logger().info('service not available, waiting again...')
        self.req = Move.Request()

    def send_request(self):
        self.req.direction = str(sys.argv[1])
        self.req.velocity = float(sys.argv[2])
        self.req.time = int(sys.argv[3])
        self.future = self.client.call_async(self.req)

def main(args=None):
    rclpy.init(args=args)
    client = ClientAsync()
    client.send_request()

    while rclpy.ok():
        rclpy.spin_once(client)
        if client.future.done():
            try:
                response = client.future.result()
            except Exception as e:
                client.get_logger().info('Service call failed %r' % (e,))
            else:
                client.get_logger().info('Response state %r' % (response.success,))
            break

    client.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

Explicação do código:

  • Importamos as bibliotecas necessárias.
  • Definimos a classe ClientAsync, que herda de Node.
  • No método __init__, criamos o cliente de serviço e esperamos que o serviço esteja disponível.
  • O método send_request envia a solicitação ao serviço com os parâmetros fornecidos.
  • No final, iniciamos e rodamos o nó ROS2.

Criando o Arquivo de Lançamento

cd ~/ros2_ws/src/movement_pkg
mkdir launch
cd launch
touch movement_server_launch_file.launch.py
chmod +x movement_server_launch_file.launch.py

Edite o arquivo movement_server_launch_file.launch.py com o seguinte conteúdo:


from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='movement_pkg',
            executable='movement_server',
            output='screen'),
    ])

Este arquivo de lançamento define um nó que executa o servidor de movimento.

Então sua estrutura de pastas e arquivos deve ficar assim:

Modificação do arquivo setup.py

Atualize o arquivo setup.py com o seguinte conteúdo:


from setuptools import setup
import os
from glob import glob

package_name = 'movement_pkg'

setup(
    name=package_name,
    version='0.0.0',
    packages=[package_name],
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
        (os.path.join('share', package_name), glob('launch/*.launch.py'))
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='user',
    maintainer_email='user@todo.todo',
    description='TODO: Package description',
    license='TODO: License declaration',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
        'movement_server = movement_pkg.movement_server:main',
        'movement_client = movement_pkg.movement_client:main'
        ],
    },
)

Este arquivo define a configuração do pacote, incluindo as entradas do console que apontam para nossos scripts Python.

Compilação e Execução

Compile o pacote movement_pkg:

cd ~/ros2_ws
colcon build --packages-select movement_pkg
source ~/ros2_ws/install/setup.bash

Lançando o Servidor

No primeiro terminal, execute:

ros2 launch movement_pkg movement_server_launch_file.launch.py

Executando o Cliente

No segundo terminal, execute:

source ~/ros2_ws/install/setup.bash
ros2 run movement_pkg movement_client left 0.2 5

No segundo terminal você verá:

Enquanto no primeiro terminal aparecerá:

Isso indica que o serviço foi realizado corretamente.

Na janela do Gazebo, você pode ver o robô se movimentando pelo ambiente.

<figure7>

Outras opções, além de left, são right, forward, backward. Experimente mudar os parametros do comando anterior variando também a velocidade e a duraçao do movimento do robô (respectivamente segundo e terceiro parametros do comando).

Conclusão

Esperamos que este tutorial tenha sido útil e que você tenha aprendido como criar serviços personalizados no ROS2 e controlar o movimento de um robô. Se você gostou deste conteúdo, considere explorar mais recursos do ROS2 e experimentar novas possibilidades para expandir suas habilidades em robótica.

 Vídeo no YouTube

Este foi o post de hoje. Lembre-se que nós temos uma versão deste post em vídeo no YouTube.

Se você gostou do conteúdo, por favor, considere se inscrever no nosso canal do YouTube. Estamos publicando novos conteúdos quase todos os dias.

Continue avançando no seu aprendizado de ROS.

 

Topics: python | ros2 | service
Masterclass 2023 batch2 blog banner

Check Out These Related Posts

129. ros2ai

129. ros2ai

I would like to dedicate this episode to all the ROS Developers who believe that ChatGPT or...

read more

0 Comments

Pin It on Pinterest

Share This