Skip to content

ROS Guide: Robot Operating System Fundamentals

Robotics Robotics 8 min read 1524 words Beginner ExcellentWiki Editorial Team

The Robot Operating System (ROS) is a framework for building robot software. It provides a structured communication layer between sensors, actuators, and algorithms through nodes, topics, services, and actions. ROS 2 is the current standard, built on DDS middleware for real-time and production use.

ROS 2 Architecture

ROS 2 improves on ROS 1 with real-time support, security, and multi-platform compatibility. Nodes communicate over DDS (Data Distribution Service), a real-time publish-subscribe middleware. The composition model allows multiple nodes to run in a single process, reducing overhead. ROS 2 supports multiple DDS implementations including Fast DDS, Cyclone DDS, and GurumDDS. Launch files in ROS 2 use Python, providing more flexibility than the XML format in ROS 1.

Core Concepts

ConceptDescriptionAnalogy
NodeA process that performs computationA program
TopicNamed bus for pub/sub communicationA message board
ServiceRequest/reply communicationA function call
ActionLong-running task with feedbackA background job with progress
BagRecording and playback of messagesA black box recorder

Nodes and Topics

A node publishes messages to topics and subscribes to topics from other nodes. This decouples producers from consumers — a camera node publishes images, and any number of processing nodes can subscribe without the camera knowing about them.

import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
from sensor_msgs.msg import LaserScan

class ObstacleAvoider(Node):
    def __init__(self):
        super().__init__('obstacle_avoider')
        self.publisher = self.create_publisher(Twist, 'cmd_vel', 10)
        self.subscription = self.create_subscription(
            LaserScan, 'scan', self.scan_callback, 10)
    
    def scan_callback(self, msg):
        # Simple obstacle avoidance
        cmd = Twist()
        min_distance = min(msg.ranges)
        if min_distance < 0.5:
            cmd.angular.z = 0.5  # turn
        else:
            cmd.linear.x = 0.2   # move forward
        self.publisher.publish(cmd)

Checking Topics

# List all topics
ros2 topic list

# See topic info
ros2 topic info /scan

# Echo messages on a topic
ros2 topic echo /odom

# Measure publishing rate
ros2 topic hz /scan

Services

Services provide synchronous request-reply communication. Use them for one-time operations like setting a parameter or triggering a calibration:

from custom_interfaces.srv import SetTarget

class TargetServer(Node):
    def __init__(self):
        super().__init__('target_server')
        self.srv = self.create_service(
            SetTarget, 'set_target', self.set_target_callback)
    
    def set_target_callback(self, request, response):
        self.get_logger().info(f'Setting target to ({request.x}, {request.y})')
        response.success = True
        response.message = 'Target updated'
        return response
# Call a service
ros2 service call /set_target custom_interfaces/srv/SetTarget "{x: 1.0, y: 2.0}"

Actions

Actions handle long-running tasks with feedback and cancelation. Use actions for navigation goals, arm movements, or complex sequences:

from custom_interfaces.action import NavigateToPose

class NavigationServer(Node):
    def __init__(self):
        super().__init__('navigation_server')
        self.action_server = ActionServer(
            self, NavigateToPose, 'navigate', self.execute_callback)
    
    async def execute_callback(self, goal_handle):
        feedback = NavigateToPose.Feedback()
        goal = goal_handle.request
        
        while not at_target(goal):
            feedback.distance_remaining = compute_distance(goal)
            goal_handle.publish_feedback(feedback)
            await asyncio.sleep(0.1)
        
        goal_handle.succeed()
        return NavigateToPose.Result(success=True)

ROS 2 CLI Tools

Essential command-line tools include ros2 node list to see running nodes, ros2 topic echo /topic_name to inspect messages, ros2 service call /service_name to invoke services, ros2 action send_goal /action_name to execute actions, and ros2 bag record -a to record all topics for later analysis and replay.

Launch Files

ROS 2 launch files are Python scripts that start multiple nodes with configuration:

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='my_robot',
            executable='camera_node',
            name='camera',
            parameters=[{'camera_id': 0}]
        ),
        Node(
            package='my_robot',
            executable='navigation_node',
            name='navigation',
        ),
    ])
ros2 launch my_robot robot.launch.py

ROS 2 Communication Patterns

Beyond basic pub-sub, ROS 2 supports several communication patterns for different needs. Services provide synchronous request-response — use for occasional operations like setting a parameter or triggering a calibration routine. Actions handle long-running tasks with feedback and preemption — ideal for navigation goals, arm movement sequences, and complex behaviors. Parameters store configurable values that nodes read at startup and can be dynamically updated. Lifecycle nodes manage deterministic startup states (unconfigured, inactive, active, finalized) for coordinating complex robot initialization sequences. Choose the pattern that matches your communication semantics for clean, maintainable code.

Summary

ROS provides a structured communication framework for robotics. Nodes publish/subscribe to topics for streaming data, call services for request/reply, and use actions for long-running tasks. ROS 2 is the current standard with DDS middleware, real-time support, and security. Use colcon for building, Python launch files for configuration, and ros2 CLI for debugging.

ROS 2 Quality of Service (QoS)

QoS settings control message delivery guarantees. Reliability can be RELIABLE (retransmit lost messages) or BEST_EFFORT (no retransmission — use for sensor data where fresh data is preferred over guaranteed delivery). Durability can be TRANSIENT_LOCAL (late-joining subscribers receive the last message) or VOLATILE (no history for late joiners). Depth sets the message queue size — deeper queues buffer more messages at the cost of latency. Publisher and subscriber QoS must be compatible: a reliable publisher with a best-effort subscriber degrades to best-effort. Choose QoS based on data criticality: use reliable for commands, best-effort for camera feeds, and transient-local for static maps.

FAQ

What is the difference between a topic and a service?

Topics are for continuous data streams (sensor data, odometry) where multiple subscribers receive data simultaneously. Services are for one-time operations (set parameter, trigger action) where you need a response. Topics are asynchronous; services are synchronous.

How do I create a custom message type?

Create a .msg file in a msg/ directory within a package. Define fields with types: float64 x, float64 y, string name. Build with colcon. Import in Python: from my_package.msg import MyMessage. In C++: #include "my_package/msg/my_message.hpp".

What is ROS 2 composition?

Composition runs multiple nodes in a single operating system process using component containers. This reduces overhead compared to running each node as a separate process. Use rclcpp_components and component_container to load shared libraries at runtime. Composition is especially beneficial for resource-constrained systems.

ROS 2 Launch Files and Parameters

ROS 2 launch system replaces ROS 1’s XML-only launch files with Python scripts that give full programmatic control. Launch files define nodes, parameters, composable node containers, and lifecycle transitions. Use LaunchConfiguration for command-line overrides: robot_name = LaunchConfiguration('robot_name'). Group actions organize nodes by namespace. Parameters can be set per-node, loaded from YAML files, or computed dynamically. Lifecycle nodes (unconfigured, inactive, active, finalized) enable deterministic startup and shutdown sequences. The launch system supports condition-based inclusion, event handlers, and remapping rules for flexible deployment across different robot configurations.

ROS 2 CLI Tools Reference

The ros2 command line tool provides comprehensive system introspection. ros2 node list shows active nodes. ros2 topic list shows available topics with types. ros2 topic echo /topic prints live messages. ros2 service list shows available services. ros2 param list shows node parameters. ros2 action list shows active action servers. ros2 interface show sensor_msgs/msg/Image displays message field definitions. ros2 run my_package my_node launches a node. ros2 launch my_package my_launch.py starts a launch file. Master these commands for efficient ROS 2 development and debugging.

Building with Colcon

Colcon is the ROS 2 build tool that compiles packages while handling dependencies. Create a workspace: mkdir -p ~/ros2_ws/src && cd ~/ros2_ws && colcon build. Build a specific package: colcon build --packages-select my_package. Build in release mode: colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release. Source the setup files: source install/setup.bash. Use colcon test to run package tests. For large workspaces, use --symlink-install to avoid recompiling when Python files change. Colcon replaces ROS 1’s catkin build system with faster, more flexible builds.

ROS 2 Ecosystem Growth

The ROS 2 ecosystem has grown to include thousands of packages spanning navigation (Nav2), manipulation (MoveIt 2), perception (PCL, OpenCV), SLAM (Cartographer, SLAM Toolbox), and robot models (Universal Robots, Fanuc, Kinova). Major hardware manufacturers provide ROS 2 drivers. Cloud integration through AWS RoboMaker, Azure Robotics, and Google Cloud provides simulation, data logging, and remote monitoring. The ecosystem maturity makes ROS 2 suitable for production deployment in warehouse logistics, manufacturing, agriculture, and service robotics.

ROS 2 vs ROS 1: Key Differences

ROS 2 differs from ROS 1 in several fundamental ways: DDS replaces the custom ROS 1 transport layer, providing built-in QoS, security, and multi-platform support. Build system changed from catkin to colcon. Launch files changed from XML to Python. ROS 2 supports real-time execution, multiple nodes per process (composition), and deterministic callback execution. ROS 1 topics were typed at connection time; ROS 2 validates types at compile time through IDL interfaces. ROS 1 nodes used a single master for discovery; ROS 2 uses DDS discovery with no single point of failure. All new development should target ROS 2 exclusively — ROS 1 support ended with Noetic in May 2025.

Troubleshooting Common ROS 2 Issues

Common ROS 2 problems and solutions: nodes not discovering each other — check firewall settings and DDS domain ID (default 0, must match across all nodes). QoS mismatch — publishers and subscribers must have compatible reliability, durability, and history settings. Clock synchronization — use chrony or ptpd for multi-machine setups. Workspace sourcing — source install/setup.bash in every terminal. Colcon build failures — clean build: rm -rf build/ install/ && colcon build. Mapping localhost to 127.0.0.1 in /etc/hosts resolves discovery issues on systems with IPv6 enabled.

How do I debug ROS 2 communication issues?

Use ros2 topic echo /topic_name to inspect messages. Use ros2 topic info to see publisher/subscriber counts. Check QoS compatibility — publishers and subscribers must have compatible QoS settings. Use RCLCPP_DEBUG or rclpy logging at DEBUG level. For network issues, check DDS discovery with fastdds discovery -i 0.

For a comprehensive overview, read our article on Ai Robotics.

For a comprehensive overview, read our article on Autonomous Mobile Robots.

Section: Robotics 1524 words 8 min read Beginner 756 articles in section Report inaccuracy Back to top