MyRoboPath
ros216 min readUpdated 2026-03-12Beginner

ROS 2 Humble Architecture: Nodes, Topics & DDS Explained

Master modern ROS 2 Humble/Iron architecture: Data Distribution Service (DDS), computational graph, publishers, subscribers, parameters, and Quality of Service (QoS).

Alex Rivera
Alex Rivera
Staff Robotics Software Engineer

Key Engineering Takeaways

  • ROS 2 eliminates the single point of failure (ROS Master) by leveraging industry-standard DDS decentralized discovery.
  • Always inherit from `rclcpp::Node` or `rclpy.node.Node` and use wall timers for deterministic periodic callbacks.
  • Use `SensorDataQoS` (Best Effort, Volatile) for high-rate sensor streams (LiDAR, Camera) and `Reliable` for critical commands (cmd_vel, E-stop).
Prerequisites
  • Linux Ubuntu terminal basics
  • Modern C++ or Python 3
Required Hardware / Tools
  • Ubuntu 22.04 LTS (Native or Dual-Boot / WSL2) with ROS 2 Humble Desktop

Why ROS 2? DDS Middleware & No Master Node

In ROS 1, if the central `roscore` process crashed, all inter-node communication halted. ROS 2 replaces this with **Data Distribution Service (DDS)**—an industrial real-time standard used in aerospace and defense. Nodes discover each other dynamically across the local network subnet via UDP multicast without needing a central coordinator.

Writing Robust C++ (rclcpp) Publisher & Subscriber Nodes

Here is a complete, modern ROS 2 C++ publisher node using smart pointers and wall timers:
velocity_commander_node.cpp
cpp
#include <chrono>
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "geometry_msgs/msg/twist.hpp"

using namespace std::chrono_literals;

class VelocityCommander : public rclcpp::Node {
public:
  VelocityCommander() : Node("velocity_commander") {
    // Declare and get ROS 2 parameters
    this->declare_parameter<double>("linear_speed", 0.5);
    this->declare_parameter<double>("angular_speed", 0.2);

    // Create publisher on /cmd_vel topic with standard queue depth of 10
    publisher_ = this->create_publisher<geometry_msgs::msg::Twist>("cmd_vel", 10);

    // Create 50Hz periodic timer (20ms interval)
    timer_ = this->create_wall_timer(
      20ms, std::bind(&VelocityCommander::publish_velocity, this)
    );

    RCLCPP_INFO(this->get_logger(), "Velocity Commander Node initialized at 50Hz.");
  }

private:
  void publish_velocity() {
    auto msg = geometry_msgs::msg::Twist();
    msg.linear.x = this->get_parameter("linear_speed").as_double();
    msg.angular.z = this->get_parameter("angular_speed").as_double();

    publisher_->publish(msg);
  }

  rclcpp::Publisher<geometry_msgs::msg::Twist>::SharedPtr publisher_;
  rclcpp::TimerBase::SharedPtr timer_;
};

int main(int argc, char *argv[]) {
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<VelocityCommander>());
  rclcpp::shutdown();
  return 0;
}
Tags:#ROS 2#Humble#rclcpp#rclpy#DDS#Nodes#Topics#QoS