ROS2 Launch File Generator
Pick the nodes you need and generate a bringup launch file and a controller launch file as a starting point — including the Gazebo resource-path exports that avoid the classic "mesh not found" / nothing-loads errors, and correctly-sequenced controller spawners.
Bringup launch file
Custom nodes
A blank starting point for any node this tool doesn't know about — fill in the package/executable, rename it, add params, and it'll drop straight into the generated file.
Controller launch file
Controllers to spawn
joint_state_broadcaster is always included first. Add the controller names exactly as they appear in your controllers.yaml — each one gets its own spawner, chained to start only after the previous one finishes (spawning them all at once can race against controller_manager and fail).
Before you run these:
- Make sure your CMakeLists.txt actually installs the urdf/, rviz/, and config/ directories (install(DIRECTORY urdf rviz config DESTINATION share/${PROJECT_NAME})) — a very common reason these paths "don't exist" is that they were never copied into the install space.
- Don't run joint_state_publisher and a real/simulated joint_state_broadcaster at the same time — they'll both try to publish /joint_states.
- These two files cover bringup + controllers only — planner/controller-server, nav2, and MoveIt config aren't generated here.
#!/usr/bin/env python3"""Bringup launch file for my_robot_description, generated by RoboticsTools.in's ROS2 Launch File Generator.""" import os from launch import LaunchDescriptionfrom launch.actions import DeclareLaunchArgument, AppendEnvironmentVariable, IncludeLaunchDescriptionfrom launch.conditions import IfConditionfrom launch.launch_description_sources import PythonLaunchDescriptionSourcefrom launch.substitutions import Command, LaunchConfiguration, PathJoinSubstitutionfrom launch_ros.actions import Nodefrom launch_ros.substitutions import FindPackageShare def generate_launch_description(): pkg_share = FindPackageShare('my_robot_description') xacro_path = PathJoinSubstitution([pkg_share, 'urdf/robot.xacro']) # Gazebo needs to find this package's meshes/models via package:// URIs, or you'll get # "mesh not found" / nothing-loads errors. This adds the share directory's parent to # Gazebo's resource search path without clobbering anything you've already sourced. set_gz_resource_path = AppendEnvironmentVariable( 'GZ_SIM_RESOURCE_PATH', PathJoinSubstitution([pkg_share, os.pardir]), ) robot_description = {'robot_description': Command(['xacro ', xacro_path])} rviz_config_path = PathJoinSubstitution([pkg_share, 'rviz/config.rviz']) robot_state_publisher_node = Node( package='robot_state_publisher', executable='robot_state_publisher', output='screen', parameters=[robot_description, {'use_sim_time': LaunchConfiguration('use_sim_time')}], ) gazebo = IncludeLaunchDescription( PythonLaunchDescriptionSource( PathJoinSubstitution([FindPackageShare('ros_gz_sim'), 'launch', 'gz_sim.launch.py']) ), launch_arguments={'gz_args': ['-r ', LaunchConfiguration('world')]}.items(), condition=IfCondition(LaunchConfiguration('use_gazebo')), ) spawn_robot_node = Node( package='ros_gz_sim', executable='create', output='screen', parameters=[{ 'name': 'my_robot', 'topic': '/robot_description', 'x': LaunchConfiguration('x'), 'y': LaunchConfiguration('y'), 'z': LaunchConfiguration('z'), 'Y': LaunchConfiguration('yaw'), }], condition=IfCondition(LaunchConfiguration('use_gazebo')), ) rviz_node = Node( package='rviz2', executable='rviz2', name='rviz2', output='screen', arguments=['-d', rviz_config_path], condition=IfCondition(LaunchConfiguration('use_rviz')), ) return LaunchDescription([ DeclareLaunchArgument('use_sim_time', default_value='true', description='Use simulation (Gazebo) clock'), DeclareLaunchArgument('use_gazebo', default_value='true', description='Launch Gazebo and spawn the robot'), DeclareLaunchArgument('world', default_value='empty.sdf', description='Gazebo world file (bundled with ros_gz_sim, or an absolute path)'), DeclareLaunchArgument('x', default_value='0', description='Spawn X position (m)'), DeclareLaunchArgument('y', default_value='0', description='Spawn Y position (m)'), DeclareLaunchArgument('z', default_value='0.1', description='Spawn Z position (m)'), DeclareLaunchArgument('yaw', default_value='0', description='Spawn yaw (rad)'), DeclareLaunchArgument('use_rviz', default_value='true', description='Launch RViz'), set_gz_resource_path, robot_state_publisher_node, gazebo, spawn_robot_node, rviz_node, ])