ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

Ros2 launch nodes in a specific order

asked 2023-03-14 05:01:19 -0500

TinyTurtle gravatar image

Hi,

I would like know, if there is a way to launch set of ros2 nodes in specific order using launch.py file Say, I have following ros2 nodes; node_1, node_2, node_3 and node_4. I would like launch node_1 only after node_2, node_3 and node_4 are launched.

Any example or code snippets are highly appreciated!!

edit retag flag offensive close merge delete

2 Answers

Sort by ยป oldest newest most voted
1

answered 2023-03-17 18:30:31 -0500

ChuiV gravatar image

If you only need to specify the order, then launch will already respect the order you specify nodes in. But if you need to have node1 wait for until nodes 2, 3, and 4 are present and running then read on.

I'm not sure exactly what criteria you have for "when a node starts", so I'm just going to use the built-in events. If you require more specific start-up conditions, you may have to write your own event, event handler, and event emitter.

Here's my python launch script to have node1 started only after nodes 2, 3, and 4 have been started. In this example "started" means that launch has processed that action, and the ProcessStarted event has been emitted.

from rclpy.node import Node
from launch import LaunchContext, LaunchDescription, LaunchService
from launch.actions import RegisterEventHandler
from launch.events.process import ProcessStarted
from launch.event_handlers.on_process_start import OnProcessStart
from launch_ros.actions import Node


def generate_launch_description():
    node1 = Node(package='demo_nodes_cpp',
                 executable='talker',
                 name='node1',
                 exec_name='node1')
    node2 = Node(package='demo_nodes_cpp',
                 executable='listener',
                 name='node2',
                 exec_name='node2')
    node3 = Node(package='demo_nodes_cpp',
                 executable='listener',
                 name='node3',
                 exec_name='node3')
    node4 = Node(package='demo_nodes_cpp',
                 executable='listener',
                 name='node4',
                 exec_name='node4')

    already_started_nodes = set()

    def start_next_node(event: ProcessStarted, context: LaunchContext):
        print(f'node {event.process_name} started.')
        already_started_nodes.update([event.process_name])
        if len(already_started_nodes) == 3:
            print(f'all required nodes are up, time to start node1')
            return node1

    return LaunchDescription([
        RegisterEventHandler(event_handler=OnProcessStart(target_action=node2,
                                                          on_start=start_next_node)),
        RegisterEventHandler(event_handler=OnProcessStart(target_action=node3,
                                                          on_start=start_next_node)),
        RegisterEventHandler(event_handler=OnProcessStart(target_action=node4,
                                                          on_start=start_next_node)),
        node2,
        node3,
        node4,
    ])


if __name__ == '__main__':
    ls = LaunchService()
    ls.include_launch_description(generate_launch_description())
    ls.run()

The three RegisterEventHandler actions will call start_next_node after the specific node has been started. Once three nodes have already been started, then we'll start node1. We could do something to look at which node actually was started, So if we needed node3 to wait until node2 to start, and node 4 to wait for node3 to start, we could do that kind of logic there.

Example output:

[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [node2-1]: process started with pid [5499]
[INFO] [node3-2]: process started with pid [5500]
[INFO] [node4-3]: process started with pid [5501]
node node2-1 started.
node node3-2 started.
node node4-3 started.
all required nodes are up, time to start node1
[INFO] [node1-4]: process started with pid [5502]
[node1-4] [INFO] [1679095729.989045466] [node1]: Publishing: 'Hello World: 1'
[node4-3] [INFO] [1679095729.990325048] [node4]: I heard: [Hello World: 1]
[node3-2] [INFO] [1679095729.990340845] [node3]: I heard: [Hello World: 1]
[node2-1] [INFO] [1679095729.990431971] [node2]: I heard: [Hello World: 1]
[node1-4] [INFO] [1679095730.988866943] [node1]: Publishing: 'Hello World: 2'
[node3-2] [INFO] [1679095730.989625772] [node3]: I heard: [Hello World: 2]
[node4-3] [INFO] [1679095730.989626316] [node4]: I heard: [Hello World: 2]
[node2-1] [INFO] [1679095730.989626457] [node2]: I heard: [Hello World: 2]
edit flag offensive delete link more

Comments

Thanks a lot @ChuiV this is exactly what I was looking for!!!

TinyTurtle gravatar image TinyTurtle  ( 2023-03-20 04:26:56 -0500 )edit
0

answered 2023-03-14 21:01:10 -0500

fury.nerd gravatar image

updated 2023-03-14 21:04:15 -0500

according to my experience , i will use a shell script to do this, an untested example needs your own completion maybe as follows:

#!/bin/bash

AMENT_PREFIX_PATH=/opt/ros/foxy         # your distro
source $AMENT_PREFIX_PATH/setup.bash
source /path/to/your/pkg/setup.bash

ros2 run pkg node1 node2> /dev/null 2>&1 &  
# in case screen flushing and set the node run background
# and pls choose your prefered launch method


i=0
while(( $i<=3 ))  # try 3 times
do
    sleep 1
    echo check for the $i time
    let i++

    node1=`ros2 node list | grep -i node1 | grep -v grep`  
    node2=`ros2 node list | grep -i node2 | grep -v grep`
    # or other critics your choose, e.g. PID


    if [[ -n $node1 && -n $node2 ]]
    then
        ros2 run pkg node3 &
        echo nodes launched
        break
    fi
done    


if [[ -z $node1 ]]
then
    echo node1 failed
fi

if [[ -z $node2 ]]
then
    echo node2 failed
fi

btw, you may need killall -i -r node to stop the background nodes...

edit flag offensive delete link more

Comments

@fury.nerd Thanks for the idea. I am specifically looking into realizing it using launch file.

TinyTurtle gravatar image TinyTurtle  ( 2023-03-16 13:06:16 -0500 )edit

hi, @TinyTurtle, how about using ros2 launch /path/to/your/launch.py instead of ros2 run pkg node in this shell script? as commented choose your prefered launch method

fury.nerd gravatar image fury.nerd  ( 2023-03-16 19:56:07 -0500 )edit

@fury.nerd, your solution is fine. But I have close to 25 nodes, checking these using shell script would be a problem, as the solution should run on linux/windows.

TinyTurtle gravatar image TinyTurtle  ( 2023-03-20 04:28:42 -0500 )edit

Question Tools

2 followers

Stats

Asked: 2023-03-14 05:01:19 -0500

Seen: 929 times

Last updated: Mar 17 '23