Generate ROS 2 Python launch files and multi-node system configurations for educational content. This skill should be used when creating lessons that teach launch file syntax, writing exercises involving multi-node startup, parameter configuration, or generating worked examples for robot system deployment.
Purpose: Generate accurate, educational ROS 2 Python launch files and multi-node configurations following official ROS 2 Humble patterns for the Physical AI textbook.
CRITICAL: Before generating any code, fetch current ROS 2 documentation using Context7 MCP:
Tool: mcp__context7__resolve-library-id
libraryName: "ros2 launch"
Then:
Tool: mcp__context7__get-library-docs
context7CompatibleLibraryID: [resolved ID]
topic: "launch file python"
This ensures launch patterns match current ROS 2 Humble API.
# File: launch/robot_system.launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='my_robot_pkg',
executable='publisher_node',
name='sensor_publisher',
output='screen',
),
Node(
package='my_robot_pkg',
executable='subscriber_node',
name='data_processor',
output='screen',
),
])
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='my_robot_pkg',
executable='configurable_node',
name='robot_controller',
output='screen',
parameters=[{
'robot_name': 'my_robot',
'update_rate': 10.0,
'max_speed': 1.5,
'enabled_sensors': ['lidar', 'camera', 'imu'],
}],
),
])
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
config = os.path.join(
get_package_share_directory('my_robot_pkg'),
'config',
'robot_params.yaml'
)
return LaunchDescription([
Node(
package='my_robot_pkg',
executable='robot_node',
name='robot_controller',
output='screen',
parameters=[config],
),
])
# File: config/robot_params.yaml
robot_controller:
ros__parameters:
robot_name: "physical_ai_bot"
update_rate: 20.0
max_linear_speed: 2.0
max_angular_speed: 1.57
sensors:
lidar:
enabled: true
topic: "/scan"
camera:
enabled: true
topic: "/image_raw"
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
def generate_launch_description():
# Declare launch arguments
robot_name_arg = DeclareLaunchArgument(
'robot_name',
default_value='default_robot',
description='Name of the robot'
)
sim_mode_arg = DeclareLaunchArgument(
'sim_mode',
default_value='true',
description='Run in simulation mode'
)
return LaunchDescription([
robot_name_arg,
sim_mode_arg,
Node(
package='my_robot_pkg',
executable='robot_node',
name='robot_controller',
output='screen',
parameters=[{
'robot_name': LaunchConfiguration('robot_name'),
'simulation': LaunchConfiguration('sim_mode'),
}],
),
])
my_robot_pkg/
├── my_robot_pkg/
│ ├── __init__.py
│ ├── publisher_node.py
│ └── subscriber_node.py
├── launch/
│ ├── robot_system.launch.py
│ └── debug_system.launch.py
├── config/
│ ├── robot_params.yaml
│ └── debug_params.yaml
├── package.xml
├── setup.py
└── setup.cfg
from setuptools import setup
import os
from glob import glob
package_name = 'my_robot_pkg'
setup(
name=package_name,
version='0.1.0',
packages=[package_name],
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
# Include launch files
(os.path.join('share', package_name, 'launch'),
glob('launch/*.launch.py')),
# Include config files
(os.path.join('share', package_name, 'config'),
glob('config/*.yaml')),
],
install_requires=['setuptools'],
entry_points={
'console_scripts': [
'publisher_node = my_robot_pkg.publisher_node:main',
'subscriber_node = my_robot_pkg.subscriber_node:main',
],
},
)
# Check system health
ros2 doctor
# Verbose output
ros2 doctor --report
# Visualize node graph
ros2 run rqt_graph rqt_graph
# In node code
self.get_logger().debug('Detailed debug info')
self.get_logger().info('Normal operation')
self.get_logger().warn('Warning condition')
self.get_logger().error('Error occurred')
self.get_logger().fatal('Fatal error')
# Set log level at runtime
ros2 run my_pkg my_node --ros-args --log-level debug
All launch files MUST work on:
Launch commands:
# Build and source
cd ~/ros2_ws
colcon build --packages-select my_robot_pkg
source install/setup.bash
# Launch
ros2 launch my_robot_pkg robot_system.launch.py
# Launch with arguments
ros2 launch my_robot_pkg robot_system.launch.py robot_name:=my_bot sim_mode:=false
colcon buildAll patterns verified against:
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer