Chapter 6: Building with ROS 2 & Python
Overview
What You'll Learn
- Create ROS 2 Python packages with proper structure
- Write launch files for multi-node systems
- Configure parameters for runtime behavior modification
- Record and playback sensor data with ROS bags
Estimated Time: 7-9 hours
Core Concepts
Concept 1: Package Structure
my_robot_pkg/
├── package.xml # Package metadata
├── setup.py # Python setup configuration
├── setup.cfg # Installation config
├── resource/ # Package marker
├── my_robot_pkg/ # Python modules
│ ├── __init__.py
│ ├── my_node.py
│ └── utils.py
├── launch/ # Launch files
│ └── robot_launch.py
├── config/ # Parameter files
│ └── params.yaml
└── test/ # Unit tests
Concept 2: Launch Files
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='my_robot_pkg',
executable='talker',
name='talker_node',
parameters=[{'topic_name': 'chatter'}]
),
Node(
package='my_robot_pkg',
executable='listener',
name='listener_node'
)
])
Concept 3: Parameters
# config/params.yaml
talker_node:
ros__parameters:
topic_name: "chatter"
publish_rate: 10.0
message_prefix: "Hello"
class ParameterNode(Node):
def __init__(self):
super().__init__('parameter_node')
# Declare parameters with defaults
self.declare_parameter('topic_name', 'default_topic')
self.declare_parameter('publish_rate', 1.0)
# Get parameter values
topic = self.get_parameter('topic_name').value
rate = self.get_parameter('publish_rate').value
Concept 4: ROS Bags
# Record all topics
ros2 bag record -a
# Record specific topics
ros2 bag record /camera/image_raw /imu/data
# Playback
ros2 bag play my_recording.db3
# Info
ros2 bag info my_recording.db3
Implementation
Tutorial: Complete Robot Package
Step 1: Create Package
cd ~/ros2_ws/src
ros2 pkg create --build-type ament_python robot_controller \
--dependencies rclpy std_msgs geometry_msgs
Step 2: Implement Node
# robot_controller/robot_controller/controller.py
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
class RobotController(Node):
def __init__(self):
super().__init__('robot_controller')
# Parameters
self.declare_parameter('max_speed', 1.0)
self.declare_parameter('update_rate', 10.0)
# Publisher
self.cmd_pub = self.create_publisher(
Twist, 'cmd_vel', 10
)
# Timer
rate = self.get_parameter('update_rate').value
self.timer = self.create_timer(1.0/rate, self.control_loop)
self.get_logger().info('Robot controller started')
def control_loop(self):
cmd = Twist()
cmd.linear.x = 0.5
cmd.angular.z = 0.1
self.cmd_pub.publish(cmd)
Step 3: Create Launch File
# launch/robot_launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
import os
from ament_index_python.packages import get_package_share_directory
def generate_launch_description():
# Get package directory
pkg_dir = get_package_share_directory('robot_controller')
# Parameter file
params_file = os.path.join(pkg_dir, 'config', 'params.yaml')
return LaunchDescription([
DeclareLaunchArgument(
'params_file',
default_value=params_file,
description='Path to parameter file'
),
Node(
package='robot_controller',
executable='controller',
name='robot_controller',
parameters=[LaunchConfiguration('params_file')],
output='screen'
)
])
Step 4: Update setup.py
from setuptools import setup
import os
from glob import glob
package_name = 'robot_controller'
setup(
name=package_name,
version='0.0.1',
packages=[package_name],
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
(os.path.join('share', package_name, 'launch'),
glob('launch/*launch.py')),
(os.path.join('share', package_name, 'config'),
glob('config/*.yaml')),
],
install_requires=['setuptools'],
entry_points={
'console_scripts': [
'controller = robot_controller.controller:main',
],
},
)
Lab Exercises
Lab 1: Multi-Node Robot System
Objective: Build system with sensor, controller, and actuator nodes
Requirements:
- Sensor node publishes simulated sensor data
- Controller processes sensor data and publishes commands
- Actuator node receives and logs commands
- Use launch file to start all nodes
- Configure behavior via parameters
Deliverables:
- Complete ROS 2 package
- Launch file starting all nodes
- Parameter file with at least 3 parameters
- README with usage instructions
Summary
Key Takeaways
- Package structure organizes code, configs, and launch files
- Launch files enable complex multi-node system startup
- Parameters allow runtime configuration without code changes
- ROS bags record sensor data for offline analysis