ROS2 Core Communication

Node

What is a node

A node is the smallest execution unit in ROS 2. Each node is a process that uses ROS 2 APIs to communicate with other nodes. In a robot system, nodes are usually split by responsibility, for example:

  • Sensor data acquisition
  • Data processing and perception
  • Motion control
  • User interaction

Node characteristics

CharacteristicDescription
LightweightA system can run many small nodes instead of one large process
DistributedNodes can run across different machines
Loosely coupledNodes communicate through topics/services/actions
ComposableMultiple nodes can be combined into larger functions
Independent lifecycleEach node can be started, stopped, and restarted independently

Node naming rules

  • Node names must be unique within the same namespace.
  • Use letters, numbers, and underscores.
  • Names are case-sensitive.
  • Prefer descriptive names, such as camera_driver or path_planner.

Hello World Node Example

Create a Python package

bash
cd ~/workspace/src
ros2 pkg create pkg_helloworld_py --build-type ament_python --dependencies rclpy --node-name helloworld

Write node code

Edit pkg_helloworld_py/pkg_helloworld_py/helloworld.py:

python
import rclpy
from rclpy.node import Node


class HelloWorldNode(Node):
    def __init__(self):
        super().__init__('helloworld')
        self.timer = self.create_timer(0.5, self.timer_callback)

    def timer_callback(self):
        self.get_logger().info('Hello World')


def main(args=None):
    rclpy.init(args=args)
    node = HelloWorldNode()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

Build and run

bash
cd ~/workspace
colcon build --packages-select pkg_helloworld_py
source install/setup.bash
ros2 run pkg_helloworld_py helloworld

Next steps

After this section, continue with:

  1. Topic communication
  2. Service communication
  3. Action communication

Topic Communication

Topic overview

What is topic communication

Topics use a publish/subscribe model. Publishers send messages to a topic, and subscribers receive messages from that topic. Publishers and subscribers do not need to know each other directly.

Topic characteristics

CharacteristicDescriptionTypical use
AsynchronousNo request/response blockingSensor streams
One-to-manyMultiple subscribers can receive the same messageData broadcast
Loosely coupledNodes only depend on topic name + message typeModular systems
Streaming-friendlyGood for continuous dataTelemetry and perception

Topic naming rules

  • Topic names can be absolute (start with /) or relative.
  • Use lowercase letters, numbers, underscores, and /.
  • Keep namespace hierarchy clear.

Examples:

  • Recommended: /cmd_vel, /camera/image_raw, /sensor/front_camera/image
  • Not recommended: /MyTopic (uppercase)

Topic communication example

Create package

bash
cd ~/workspace/src
ros2 pkg create pkg_topic --build-type ament_python --dependencies rclpy std_msgs --node-name publisher_demo

Publisher (publisher_demo.py)

python
import rclpy
from rclpy.node import Node
from std_msgs.msg import String


class TopicPub(Node):
    def __init__(self):
        super().__init__('publisher_node')
        self.pub = self.create_publisher(String, '/topic_demo', 10)
        self.timer = self.create_timer(1.0, self.pub_msg)

    def pub_msg(self):
        msg = String()
        msg.data = 'Hi, I send a message.'
        self.pub.publish(msg)


def main(args=None):
    rclpy.init(args=args)
    node = TopicPub()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

Subscriber (subscriber_demo.py)

python
import rclpy
from rclpy.node import Node
from std_msgs.msg import String


class TopicSub(Node):
    def __init__(self):
        super().__init__('subscriber_node')
        self.sub = self.create_subscription(String, '/topic_demo', self.sub_callback, 10)

    def sub_callback(self, msg):
        self.get_logger().info(msg.data)


def main(args=None):
    rclpy.init(args=args)
    node = TopicSub()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

Update setup.py

Add console scripts:

python
'publisher_demo = pkg_topic.publisher_demo:main',
'subscriber_demo = pkg_topic.subscriber_demo:main',

Build and run

bash
cd ~/workspace
colcon build --packages-select pkg_topic
source install/setup.bash

Terminal A:

bash
ros2 run pkg_topic publisher_demo

Terminal B:

bash
ros2 run pkg_topic subscriber_demo

Optional verification:

bash
ros2 topic list
ros2 topic echo /topic_demo

Service Communication

Service overview

What is service communication

Services use request/response communication. A client sends a request, and a server processes it and returns a response.

Services vs topics

FeatureServicesTopics
PatternRequest/responsePublish/subscribe
Sync behaviorUsually synchronous from caller perspectiveAsynchronous
Best forShort operations and queriesContinuous streams
Return valueRequiredNot required

Service interface example

example_interfaces/srv/AddTwoInts:

  • Request: int64 a, int64 b
  • Response: int64 sum

Service communication example

Create package

bash
cd ~/workspace/src
ros2 pkg create pkg_service --build-type ament_python --dependencies rclpy example_interfaces --node-name server_demo

Service server (server_demo.py)

python
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts


class ServiceServer(Node):
    def __init__(self):
        super().__init__('service_server')
        self.srv = self.create_service(AddTwoInts, '/add_two_ints', self.callback)

    def callback(self, request, response):
        response.sum = request.a + request.b
        self.get_logger().info(f'request: a={request.a}, b={request.b}, sum={response.sum}')
        return response


def main(args=None):
    rclpy.init(args=args)
    node = ServiceServer()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

Service client (client_demo.py)

python
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts


class ServiceClient(Node):
    def __init__(self):
        super().__init__('service_client')
        self.client = self.create_client(AddTwoInts, '/add_two_ints')
        while not self.client.wait_for_service(timeout_sec=1.0):
            self.get_logger().info('service not available, waiting...')

    def send_request(self, a, b):
        req = AddTwoInts.Request()
        req.a = a
        req.b = b
        return self.client.call_async(req)


def main(args=None):
    rclpy.init(args=args)
    node = ServiceClient()
    future = node.send_request(10, 90)
    rclpy.spin_until_future_complete(node, future)
    if future.result() is not None:
        node.get_logger().info(f'Result: {future.result().sum}')
    else:
        node.get_logger().error('Service call failed')
    node.destroy_node()
    rclpy.shutdown()

Update setup.py

python
'server_demo = pkg_service.server_demo:main',
'client_demo = pkg_service.client_demo:main',

Build and run

bash
cd ~/workspace
colcon build --packages-select pkg_service
source install/setup.bash

Terminal A:

bash
ros2 run pkg_service server_demo

Terminal B:

bash
ros2 run pkg_service client_demo

Manual CLI test:

bash
ros2 service list
ros2 interface show example_interfaces/srv/AddTwoInts
ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 1, b: 4}"

Action Communication

Action overview

What is action communication

Actions are designed for long-running tasks that need:

  • Progress feedback during execution
  • Final result when done
  • Optional cancellation while running

Action vs service

FeatureActionService
Task durationLong-runningShort
FeedbackSupportedNot supported
CancellationSupportedNot supported
Return modelGoal + Feedback + ResultRequest + Response

Action communication example

You can quickly verify actions with turtlesim:

  1. Start turtlesim:
bash
ros2 run turtlesim turtlesim_node
  1. Send an action goal:
bash
ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: 1.57}"
  1. Watch available actions and interfaces:
bash
ros2 action list
ros2 action info /turtle1/rotate_absolute
ros2 interface show turtlesim/action/RotateAbsolute

Expected result:

  • The turtle rotates to the target angle.
  • The action returns a final result when complete.

Next steps

After core communication, continue with:

  1. ROS 2 advanced interfaces and middleware
  2. ROS 2 tools and launch
  3. ROS 2 simulation and vision