Introduction to ROS 2: The Future of Robotics Software

Robots are no longer futuristic fantasies, they are shaping our present. From autonomous delivery systems to smart home assistants and self-navigating drones, robots rely heavily on reliable software frameworks to function. One such powerful and widely adopted framework is ROS; the Robot Operating System. But today, we're not just talking about ROS. We're diving into ROS 2, the next-generation version that is fast becoming the standard for modern robotics projects.

What is ROS2?



ROS 2 (Robot Operating System 2) is an open-source framework for developing robot software. Despite its name, it's not an operating system like Windows or Linux, but rather a middleware, a collection of tools, libraries, and conventions that help you build complex and distributed robot applications.

ROS 2 is a complete redesign of the original ROS 1 framework. It was created to address the limitations of ROS 1 and to support real-world production systems more effectively.

Why Use ROS 2 Humble Hawksbill?



In this blog series, you’ll realize that we are using ROS2 Humble, which was released on 23rd May 2022(World Turtle Day). It is one of the Long-Term Support (LTS) versions of ROS2, which means it is maintained and receives security updates for several years (until May 2027).

Basic Concepts of ROS 2

ROS 2 is a middleware based on a strongly-typed, anonymous publish/subscribe mechanism that allows for message passing between different processes.

In this blog we’ll learn about the following concepts:

  • Nodes

  • Interfaces

  • Topics

  • Services

  • Actions

  • Discovery

  • Parameters

  • ROS2 command line tools

  • Launch

  • Client libraries

1. Nodes

In ROS 2, a node refers to a single process that handles a specific part of a robot's overall functionality. Rather than having all operations bundled into one place, a robot’s behavior is distributed across multiple nodes. For example, one node might handle sensor input, while another manages motor control.

These nodes can interact with each other whether they’re in the same process, separate processes, or even running on different machines entirely. Communication typically happens through named topics, where nodes either publish information for others to consume or subscribe to receive relevant data streams.

Beyond topic-based messaging, nodes can also use services to request specific computations from other nodes (as clients), or offer services themselves (as servers). For tasks that are long-running or require feedback over time—such as navigation goals—actions are used in a similar client-server pattern.

A single node can take on multiple roles simultaneously: acting as a publisher, subscriber, service provider, client, action server, or action client, depending on what the robot’s tasks demand. Parameters can also be used to tweak a node’s behavior at runtime, offering flexibility during development or operation.

2. Interfaces

ROS 2 applications exchange data through three primary communication interfaces: topics, services, and actions. To describe these interfaces, ROS 2 utilizes a simplified specification format known as the Interface Definition Language (IDL). This allows for automatic generation of source code in multiple programming languages, streamlining development.

We will discuss the following supported types:

  • .msg (Message files): These are plain-text files that list the structure of a message, specifying each field and its data type. They serve as templates from which ROS tools generate message-handling code in various languages.

  • .srv (Service files): These files define a service interaction by outlining two message structures: a request and a response. Each part is declared similarly to a message file.

  • .action(Action files): These describe more complex, long-running tasks. An action definition consists of three parts: a goal, a result, and feedback—each structured like a message.

Breaking down each interface type:

i. Messages

Messages are a way for a ROS 2 node to send data on the network to other ROS nodes, with no response expected. For instance, if a ROS 2 node reads temperature data from a sensor, it can then publish that data on the ROS 2 network using a Temperature message. Other nodes on the ROS 2 network can subscribe to that data and receive the Temperature message.

Another example is as shown below:

ii. Services

Services follow a request-response model. When a node needs a quick computation or a specific action performed, it can send a request to a service server, which processes the input and sends back a result. This is ideal for short, synchronous operations.

iii. Actions

Actions extend the service model to support long-duration tasks. Unlike services, action clients can receive feedback during execution, know when the task has been completed (result), and even cancel the operation midway if necessary. This makes actions suitable for processes such as robot navigation or manipulation, where progress updates and potential interruption are valuable.

3. Topics

Among the three main communication mechanisms in ROS 2, topics are the go-to choice for handling continuous streams of data. They're ideal for use cases like publishing sensor readings, robot status updates, or any other time-sensitive information that needs to be shared across components.

  • Example: A LiDAR sensor node might continuously send scan data to the /scan topic, while a mapping node listens (subscribes) to that topic in order to construct an environment map.

i. Publish/Subscribe Model

ROS 2 topics operate on a publish/subscribe architecture. In this model:

  • Publishers are nodes that generate and send data.

  • Subscribers are nodes that receive and process that data.

The common ground for both is the topic name. When a publisher and a subscriber use the same topic identifier, they’re able to communicate. You define the topic name when you create a publisher or a subscriber, and ROS 2 uses this shared label to route the messages accordingly.

When data is published to a topic, all active subscribers connected to that topic receive the information. This approach resembles an electrical bus system, where multiple devices are connected to the same channel—making the architecture both scalable and modular.

ii. Anonymous Communication

ROS 2 communication is inherently anonymous. This means subscribers don’t inherently track the identity of the publishers sending them data—nor do they need to. This decouples components in the system, allowing developers to freely swap, upgrade, or modify publishers and subscribers independently, as long as they adhere to the expected message structure and topic name.

iii. Strongly-typed

ROS 2 enforces strong typing at two levels:

  1. Field-level typing: Every field in a ROS message must follow its declared type. For example:

    uint32 field1 string field2

    This definition ensures that field1 is always an unsigned 32-bit integer, and field2 is strictly a string. Any violations will be caught at runtime or during message generation.

  2. Semantic consistency: While not enforced programmatically, ROS message types come with well-defined semantics. Take the IMU message, for instance—it includes a 3D vector representing angular velocity, with each axis measured in radians per second. Developers are expected to adhere to these conventions to maintain data integrity and interoperability.

4. Services

While topics are ideal for continuous data flow, there are times when a node needs a direct, on-demand response. This is where services come in. Services in ROS 2 enable request-response interactions, similar to remote procedure calls (RPCs). A node can expose a service, and any other node can invoke it when specific tasks need to be performed.

  • Example: A node may offer a service to reset the robot's position, and another node can call it when needed.

ROS 2 services are designed for quick, short-lived tasks. Since the client waits for a result, these operations should return swiftly. Long-duration tasks are discouraged in services—especially those that may need to be interrupted—making actions a better fit for such scenarios.

Services are addressed using a unique name, similar in appearance to topic names, but separated under a different namespace to avoid conflict.

A service consists of two parts: the service server and the service client.

i. Service Server

The service server is the component that listens for incoming requests and processes them. It receives the request, performs the computation, and sends back a result. For instance, suppose the ROS 2 message contains the following:

uint32 a uint32 b --- uint32 sum

In this case, the server takes two integers (a and b), calculates their sum, and responds with the result.

There should only ever be one service server per service name. It is undefined which service server will receive client requests in the case of multiple service servers on the same service name.

ii. Service Client

The service client initiates a request to the server, waits for the response, and proceeds based on the returned data.

Using the same example above, the client sends the values a and b to the service, and then waits to receive the sum.

Unlike the service server, there can be arbitrary numbers of service clients using the same service name.

5. Actions



Some operations take time—navigating to a goal, performing complex calculations, or manipulating a robot arm. For such long-running tasks, ROS 2 uses actions. Actions extend the service model by allowing progress feedback, cancellation, and preemption during execution.

  • Example: A robot's state machine might instruct the navigation stack to drive to a waypoint. This could take minutes, during which the robot reports progress (e.g., distance remaining), and the state machine retains the ability to cancel the mission.

This structure is reflected in how an action message definition looks:

int32 request --- int32 response --- int32 feedback

Actions are also associated with a unique name, structured similarly to topics and services but placed under a different namespace. Like services, only one action server should be active under a given name.

An action consists of two parts: the action server and the action client.

i. Action Server

The action server receives the request, executes the task, and sends back ongoing feedback during execution. Once the task is complete—or cancelled—it provides the final result.

For instance, consider an action to calculate the Fibonacci sequence with the following interface:

int32 order --- int32[] sequence --- int32[] sequence

The action server is the entity that receives this message, starts calculating the sequence up to order (providing feedback along the way), and finally returns a full result in sequence.

There should only ever be one action server per action name. It is undefined which action server will receive client requests in the case of multiple action servers on the same action name.

ii. Action Client

The action client initiates a request and receives feedback as the task progresses. It can also cancel or modify the request if needed.

Using the Fibonacci example, the client sends the order, listens for feedback (intermediate numbers), and finally receives the full sequence.

Unlike the action server, there can be arbitrary numbers of action clients using the same action name.

6. Discovery

One of the powerful features of ROS 2 is its ability to automatically discover nodes across a network. This happens through the underlying DDS-based middleware, which handles the complexity of discovery and connection management.

When a node starts up, it broadcasts its presence to other nodes that share the same ROS domain, a logical grouping defined by the ROS_DOMAIN_ID environment variable. Other nodes that hear this broadcast reply with their own metadata, allowing the middleware to establish communication paths between compatible publishers and subscribers.

This isn’t a one-time process—nodes periodically re-advertise themselves. This means that even if a node starts late or reconnects after a temporary disconnection, it can still discover and sync with existing nodes. Likewise, when a node shuts down, it signals its departure so that others can update their communication graphs accordingly.

Example: If you run the classic talker-listener demo—launching the C++ talker node in one terminal and the Python listener node in another—you’ll observe that they automatically detect each other and begin exchanging messages over the shared topic, without any manual setup.



7. Parameters

Parameters allow you to fine-tune node behavior at runtime—without changing the source code. Each parameter belongs to a specific node and can be used to adjust things like threshold values, update rates, or movement limits.

The lifetime of a parameter is tied to the node that owns it. However, with some logic, a node can persist parameters across restarts by saving and reloading them.

Parameters are addressed by node name, node namespace, parameter name, and parameter namespace. Providing a parameter namespace is optional.

ROS 2 uses namespaces to keep things organized, especially in complex or multi-robot systems. These namespaces act like folders in a filesystem, helping you avoid naming collisions and keep node configurations modular and maintainable. 

Here’s a brief overview on Parameters background:

i. Declaring parameters

Before a node can use a parameter, it must declare it—this establishes the expected name and type of the parameter. Declaring parameters up front helps catch configuration issues early and ensures type safety.

That said, for dynamic applications where not all parameters are known at startup, you can enable allow_undeclared_parameters. This lets the node accept and use parameters that haven’t been declared, offering flexibility at the cost of strict validation.

ii. Parameter Types

Each parameter must conform to one of the predefined types (e.g., int, bool, string). Once a parameter is declared with a specific type, its type cannot be changed at runtime—this protects against mismatches like assigning a string to an integer parameter.

If your application needs more flexibility, you can declare a parameter using a ParameterDescriptor with dynamic_typing set to true. This allows the parameter to change types dynamically, assuming your node logic can handle it.

iii. Parameter Callbacks

ROS 2 supports parameter callbacks so that nodes can respond to changes in parameter values:

  • Set Parameter Callback: This function lets you validate or reject changes before they’re applied. You register it with add_on_set_parameters_callback, and it receives a list of proposed changes to inspect.

  • Parameter Event Callback: This one is notification-only. You register it using on_parameter_event, and it triggers after parameter values are updated. It’s useful for logging, triggering actions, or syncing configuration elsewhere.

iv. Setting initial parameter values when running a node

You can initialize parameters when launching a node:

  • Using command-line arguments, e.g., ros2 run your_package your_node --ros-args -p speed:=1.0

  • Or by loading a YAML file that defines multiple parameters in a structured format.

v. Setting initial parameter values when launching nodes

Initial parameter values can also be set when running the node through the ROS 2 launch facility.

vi. Changing parameter values at runtime

For nodes already running, you can interact with parameters using the ros2 param CLI tool. This interface lets you:

  • List existing parameters

  • Set or get parameter values

  • Describe parameter types

  • Monitor parameter changes

Behind the scenes, ros2 param uses the parameter services API to communicate with nodes, offering a clean way to reconfigure systems without restarting them.


8. ROS2 command line tools

ROS 2 offers a powerful command-line interface (CLI) that allows developers to inspect, manage, and interact with various parts of the ROS ecosystem. All CLI interactions begin with the ros2 command, which provides access to a wide range of subcommands designed to operate on nodes, topics, services, and more.

To see all available sub-commands run:

ros2 --help

Some commonly used subcommands include:

  • ros2 action – Interact with and inspect ROS 2 actions

  • ros2 bag – Record and replay message data (rosbags)

  • ros2 component – Manage nodes in component containers

  • ros2 daemon – Check and control the ROS 2 daemon

  • ros2 doctor – Diagnose potential issues in your ROS 2 setup

  • ros2 interface – View message, service, and action definitions

  • ros2 launch – Start a group of nodes defined in a launch file

  • ros2 lifecycle – Manage lifecycle states of nodes

  • ros2 multicast – Send/receive multicast debug information

  • ros2 node – Discover and introspect active nodes

  • ros2 param – Configure or view node parameters

  • ros2 pkg – Explore installed ROS packages

  • ros2 run – Start individual ROS nodes

  • ros2 security – Set up and manage security credentials

  • ros2 service – Call and inspect services

  • ros2 test – Run ROS 2 launch tests

  • ros2 topic – Publish to or echo topics in real-time

  • ros2 trace – Trace system execution (Linux only)

  • ros2 wtf – Shortcut alias for ros2 doctor

Example: To produce the typical talker-listener example using command-line tools, the topic sub-command can be used to publish and echo messages on a topic.

Publish messages in one terminal with the following command:

ros2 topic pub /chatter std_msgs/msg/String "data: Hello world"

You will see from that terminal the following message:

publisher: beginning loop publishing #1: std_msgs.msg.String(data='Hello world') publishing #2: std_msgs.msg.String(data='Hello world')

Echo messages received in another terminal with the following command:

ros2 topic echo /chatter

Expected output in this other terminal is as follows:

data: Hello world data: Hello world

9. Launch

Managing multiple nodes manually becomes inefficient as a system scales. To solve this, ROS 2 provides a launch system that automates the process of starting and configuring multiple nodes with a single command.

A launch file defines:

  • Which nodes to start

  • How to configure them

  • What arguments or parameters to pass

  • Where to execute them

  • How to monitor and manage their lifecycle

Launch files can be written in Python, XML, or YAML, offering flexibility in structuring and customizing your robot system.

To start a launch file:

ros2 launch <package_name> <file_name.launch.py>

Once triggered, ROS 2 starts all the defined nodes with the specified configuration and continues to monitor their health and status—making it easy to manage complex systems, even across distributed machines.

10. Client Libraries

Client libraries serve as the bridge between your programming language of choice and the core functionality of ROS 2. They provide the tools needed to write nodes, interact with topics and services, and manage communication between components in a ROS 2 system.

ROS 2 supports multiple programming languages through these client libraries. This flexibility allows developers to choose the best tool for the job—for example, using Python for rapid prototyping or C++ for performance-critical applications.

Despite the differences in language, all client libraries rely on a shared core (called rcl) and follow a unified structure for message generation. This means nodes written in different languages can still communicate seamlessly.

Key Features Available via Client Libraries

Regardless of language, client libraries give developers access to essential ROS 2 functionality, including:

  • Names and namespaces

  • Time (real or simulated)

  • Parameters

  • Console logging

  • Threading model

  • Intra-process communication

i. Supported Client libraries

The C++ client library (rclcpp) and the Python client library (rclpy) are both client libraries which utilize common functionality in rcl.

a. The rclcpp package- C++ Client Library

rclcpp is the main C++ interface for writing ROS 2 applications. Built on top of the shared C API (rcl), it offers an idiomatic, modern C++ experience by leveraging features from C++17.

With rclcpp, you can create nodes, publish or subscribe to topics, handle services and actions, and manage parameters—all using ROS-native C++ messages generated from .msg files.

Its close integration with the core API ensures compatibility with other client libraries and consistent runtime behavior.

b. The rclpy package

rclcpp is the main C++ interface for writing ROS 2 applications. Built on top of the shared C API (rcl), it offers an idiomatic, modern C++ experience by leveraging features from C++17.

With rclcpp, you can create nodes, publish or subscribe to topics, handle services and actions, and manage parameters—all using ROS-native C++ messages generated from .msg files.

Its close integration with the core API ensures compatibility with other client libraries and consistent runtime behavior.

ROS2 in Action

Using ROS 2 Humble, you can:

  • Build SLAM-enabled robots with real-time LiDAR data.

  • Simulate robots in environments like Gazebo.

  • Develop autonomous vehicles with Nav2.

  • Easily scale systems across multiple devices or networks.

Conclusion

If you're stepping into the world of robotics, ROS 2 Humble offers the perfect mix of stability, community support, and modern features. Understanding the core concepts—nodes, topics, messages, services, and more—lays the foundation for building powerful robot applications.

In the upcoming sections, we'll guide you through installing ROS 2, setting up your first workspace, and writing your first nodes. So stay tuned—your robotics journey is just getting started!

Next Blog:

Installing ROS2 Humble: https://roboticsdojo.blogspot.com/2025/07/beginners-guide-to-ros-2-humble.html

References:
  1. https://docs.ros.org/en/humble/Concepts/Basic.html

  2. https://www.electronicdesign.com/markets/automation/article/21214053/electronic-design-ros-2-explained-overview-and-features

  3. https://docs.ros.org/en/kilted/Releases.html

Comments

Popular posts from this blog

Getting Started with ROS2 Humble: Workspace, Packages, and Nodes

CREATING A PUBLISHER AND SUBSCRIBER NODES USING PYTHON

The Raspberry Pi