1
$\begingroup$

Rosanswers logo

Question
Is there any possibility to call a service from a launch.py file in ROS2?

Details
I have written a python node with a service which is launched by a launch.py file. Within the same launch file I would like to call the service of this node multiple times (with different argument values). Is there any possibility to realize this in ROS2?

Reference
call-a-service-at-startup-with-a-launch-file


Originally posted by ffent on ROS Answers with karma: 21 on 2021-08-18

Post score: 2

$\endgroup$

3 Answers 3

1
$\begingroup$

Rosanswers logo

This one is pretty straight forward, but took me a non-trivial amount of searching to find for myself. I posted this answer somewhere else recently, but since this question is the top search result, I thought I'd copy it here as well.

from launch.substitutions import FindExecutable
from launch.actions import ExecuteProcess

...

ld.add_action(
    ExecuteProcess(
        cmd=[[
            FindExecutable(name='ros2'),
            " service call ",
            "/namespace/service_to_call ",
            "example_msgs/srv/ExampleMsg ",
            '"{param_1: True, param_2: 0.0}"',
        ]],
        shell=True
    )
)

Note the following:

  • ld here is a variable containing an instance of LaunchDescription
  • /namespace/service_to_call is replaced with the service you're looking to call (don't forget any appropriate namespaces) and can be found with ros2 service list
  • example_msgs/srv/ExampleMsg is the message type used by that service, which you can get with ros2 service info /namespace/service_to_call
  • "{param_1: True, param_2: 0.0}" is the dictionary defining the message data. To find the parameters you need to set, you may need to consult the .srv file or documentation.

Don't forget to include the shell=True argument, as the command will fail with a confusing "File not found" error without it.


Originally posted by luckierdodge with karma: 56 on 2022-09-04

This answer was ACCEPTED on the original site

Post score: 4

$\endgroup$
0
$\begingroup$

Rosanswers logo

Thanks @luckierdodge! Just add more methods. Both examples below start a sim window and add another turtle2.

Method 1

Based on @luckierdodge answer:

from launch import LaunchDescription
from launch.actions import ExecuteProcess
from launch.substitutions import FindExecutable
from launch_ros.actions import Node


def generate_launch_description():
    ld = LaunchDescription(
        [
            Node(
                package="turtlesim",
                executable="turtlesim_node",
                name="turtlesim",
            ),
        ]
    )
    ld.add_action(
        ExecuteProcess(
            cmd=[
                [
                    FindExecutable(name="ros2"),
                    " service call ",
                    "/spawn ",
                    "turtlesim/srv/Spawn ",
                    "\"{x: 2.0, y: 2.0, theta: 0.0, name: 'turtle2'}\"",
                ]
            ],
            shell=True,
        )
    )
    return ld

Method 2

Based on https://docs.ros.org/en/humble/Tutorials/Intermediate/Launch/Using-Event-Handlers.html

from launch import LaunchDescription
from launch.actions import ExecuteProcess, LogInfo, RegisterEventHandler
from launch.event_handlers import OnProcessStart
from launch.substitutions import FindExecutable, LaunchConfiguration
from launch_ros.actions import Node


def generate_launch_description():
    turtlesim_node = Node(
        package="turtlesim",
        executable="turtlesim_node",
        name="sim",
    )
    spawn_turtle = ExecuteProcess(
        cmd=[
            [
                FindExecutable(name="ros2"),
                " service call ",
                "/spawn ",
                "turtlesim/srv/Spawn ",
                "\"{x: 2.0, y: 2.0, theta: 0.0, name: 'turtle2'}\"",
            ]
        ],
        shell=True,
    )
    return LaunchDescription(
        [
            turtlesim_node,
            RegisterEventHandler(
                OnProcessStart(
                    target_action=turtlesim_node,
                    on_start=[
                        LogInfo(msg="Turtlesim started, spawning turtle"),
                        spawn_turtle,
                    ],
                )
            ),
        ]
    )

Originally posted by Hongbo Miao with karma: 70 on 2023-01-01

This answer was NOT ACCEPTED on the original site

Post score: 1

$\endgroup$
0
$\begingroup$

Here is what I found works with Services that have multiple/multiline arguments:

Humble, Ubuntu 22

i.e., this is the command line:

ros2 service call /namespace/service_to_call example_msgs/srv/ExampleMsg "param_1: {x: 0.0, y: 0.0, z: 0.0}
param_2: {x: -500.0, y: 160.0, z: -10.0}  
param_3: 0.05 
param_4: 0.001"

To run this from a launch file, I had to resort to this:

def generate_launch_description():

    # start  service
    # Define service name, message type, and service arguments (as strings)
    my_service_name = "/namespace/service_to_call"
    my_service_type = "example_msgs/srv/ExampleMsg"
    my_service_arguments = f"""
    param_1: {{x: 0.0, y: 0.0, z: 0.0}}
    param_2: {{x: -500.0, y: 160.0, z: -10.0}}  
    param_3: 0.05 
    param_4: 0.001 
    """

    # Construct the complete command string
    command = f"ros2 service call {my_service_name} {my_service_type} '{my_service_arguments}'"

    my_service_call = ExecuteProcess(
        cmd=[command],
        shell=True,  # **Caution:** Using shell=True increases security risk
    )

    return LaunchDescription([my_service_call])
  • Notice the extra { } in the python f string.

Honestly, I am not sure what the point of FindExecutable(name='ros2') is if I am just running a shell command from the launch file.

It would be much nicer if I could pass the service parameters from a YAML file, but I could not find any example so far...

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.