1+ import os
2+ from ament_index_python .packages import get_package_share_directory
3+ from launch import LaunchDescription
4+ from launch .actions import DeclareLaunchArgument , OpaqueFunction
5+ from launch .substitutions import LaunchConfiguration
6+ from launch_ros .actions import Node
7+
8+
9+ def launch_setup (context , * args , ** kwargs ):
10+ """
11+ Dynamically determine package name and configuration path.
12+
13+ This function is called by OpaqueFunction to resolve launch arguments
14+ and create the Node action.
15+ """
16+ # These values are resolved from the DeclareLaunchArgument definitions below
17+ package_name = LaunchConfiguration ('package_name' ).perform (context )
18+ executable_name = LaunchConfiguration ('executable_name' ).perform (context )
19+ node_name = LaunchConfiguration ('node_name' ).perform (context )
20+
21+ # Construct the path to the parameter file within the current package
22+ # This assumes your params.yaml is in a 'config' subdirectory within your package's share directory.
23+ param_file_path = os .path .join (
24+ get_package_share_directory (package_name ),
25+ 'config' ,
26+ 'params.yaml' # <-- REPLACE if your parameter file has a different name
27+ )
28+
29+ # Check if the params.yaml file actually exists
30+ node_parameters = []
31+ if os .path .exists (param_file_path ):
32+ node_parameters .append (param_file_path )
33+ print (f"INFO: Using parameter file for { node_name } : { param_file_path } " )
34+ else :
35+ print (f"WARNING: No params.yaml found for { node_name } at { param_file_path } . Launching without parameters." )
36+
37+
38+ # Define the Node action
39+ node = Node (
40+ package = package_name ,
41+ executable = executable_name ,
42+ name = node_name ,
43+ parameters = node_parameters ,
44+ output = 'screen' , # Optional: 'screen' or 'log'. 'screen' prints output to the console.
45+ emulate_tty = True , # Optional: Set to True for colored output in the console.
46+ )
47+
48+ return [node ]
49+
50+
51+ def generate_launch_description ():
52+ """
53+ Generate the launch description for a generic ROS 2 package.
54+
55+ This template is designed to be placed in any ROS 2 package's
56+ launch directory. It expects the package to have a main executable
57+ and optionally a 'config/params.yaml' file.
58+ """
59+ return LaunchDescription ([
60+ # Declare the package name argument.
61+ # This argument specifies WHICH ROS 2 package this launch file should target.
62+ # When running, you will set this:
63+ # e.g., ros2 launch <path_to_this_launch_file> generic_package.launch.py package_name:=your_actual_package_name
64+ DeclareLaunchArgument (
65+ 'package_name' ,
66+ description = 'Name of the ROS 2 package to launch.'
67+ ),
68+ # Declare the executable name argument.
69+ # This argument specifies WHICH executable within the 'package_name' should be run.
70+ # When running, you will set this:
71+ # e.g., ros2 launch ... executable_name:=your_node_executable_name
72+ DeclareLaunchArgument (
73+ 'executable_name' ,
74+ description = 'Name of the executable to run from the package.'
75+ ),
76+ # Declare the node name argument (optional, defaults to executable_name)
77+ # This argument sets the ROS 2 node name. If not provided, it defaults to the executable name.
78+ # e.g., ros2 launch ... node_name:=my_custom_node_name
79+ DeclareLaunchArgument (
80+ 'node_name' ,
81+ default_value = LaunchConfiguration ('executable_name' ), # Defaults to the executable name
82+ description = 'Name to assign to the ROS 2 node.'
83+ ),
84+ # OpaqueFunction defers the creation of the Node action until launch arguments are resolved.
85+ # This is necessary because we need the actual string values of package_name, executable_name, etc.
86+ OpaqueFunction (function = launch_setup )
87+ ])
0 commit comments