Skip to main content
Home/Guides/ROS 2 Getting Started 2026
🤖 Developer GuideUpdated June 2026 · ROS 2 Jazzy / Humble

ROS 2 Getting Started Guide 2026

Complete setup from zero to autonomous navigation. Covers Ubuntu 22.04/24.04, first node, Nav2, Docker DevContainer, and real hardware integration.

ROS 2 Jazzy JaliscoUbuntu 24.04 · LTS until May 2029
ROS 2 Humble HawksbillUbuntu 22.04 · LTS until May 2027

1. Installation

Set locale and add ROS 2 GPG key

Ensure UTF-8 locale and add the ROS 2 apt repository.

# Set UTF-8 locale
locale  # check for UTF-8
sudo apt update && sudo apt install locales
sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
export LANG=en_US.UTF-8

# Add ROS 2 GPG key
sudo apt install software-properties-common curl -y
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key   -o /usr/share/keyrings/ros-archive-keyring.gpg

# Add ROS 2 repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg]   http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main"   | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

Install ROS 2 Jazzy (Ubuntu 24.04) or Humble (22.04)

Install the full desktop version including RViz2, simulation tools, and demos.

sudo apt update && sudo apt upgrade -y

# Ubuntu 24.04 → ROS 2 Jazzy (LTS, supported until May 2029)
sudo apt install ros-jazzy-desktop -y

# Ubuntu 22.04 → ROS 2 Humble (LTS, supported until May 2027)
# sudo apt install ros-humble-desktop -y

# Development tools
sudo apt install python3-colcon-common-extensions   python3-rosdep python3-vcstool -y

# Initialize rosdep
sudo rosdep init && rosdep update

💡 Always install the latest LTS distro for your Ubuntu version. Jazzy on Ubuntu 24.04 is recommended for new projects in 2026.

Source the setup file and add to .bashrc

Source ROS 2 environment variables in every terminal session.

# Source for current terminal
source /opt/ros/jazzy/setup.bash

# Auto-source in every new terminal
echo "source /opt/ros/jazzy/setup.bash" >> ~/.bashrc
source ~/.bashrc

# Verify installation
ros2 --version  # should print: ros2 2.x.x (Jazzy)

Test with demo_nodes

Run the canonical talker/listener demo to verify your installation.

# Terminal 1: start talker
ros2 run demo_nodes_cpp talker

# Terminal 2: start listener
ros2 run demo_nodes_cpp listener

# Expected output in listener terminal:
# [INFO] [1718000000.000000000] [listener]: I heard: [Hello World: 0]
# [INFO] [1718000000.000000000] [listener]: I heard: [Hello World: 1]

2. First Package & Node

Create a colcon workspace, scaffold a Python package, and write your first publisher node.

Create a workspace

ROS 2 uses colcon workspaces. Create the standard src/build/install layout.

mkdir -p ~/ros2_ws/src
cd ~/ros2_ws
# Build empty workspace to initialize
colcon build
source install/setup.bash

Create your first package

Use ros2 pkg create to scaffold a Python package with a publisher node.

cd ~/ros2_ws/src
ros2 pkg create my_robot_pkg \
  --build-type ament_python \
  --dependencies rclpy std_msgs

Write a publisher node

Replace the placeholder in my_robot_pkg/my_robot_pkg/my_node.py:

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

class MinimalPublisher(Node):
    def __init__(self):
        super().__init__('minimal_publisher')
        self.publisher_ = self.create_publisher(String, 'robot_status', 10)
        self.timer = self.create_timer(0.5, self.timer_callback)
        self.i = 0

    def timer_callback(self):
        msg = String()
        msg.data = f'Robot status: {self.i}'
        self.publisher_.publish(msg)
        self.get_logger().info(f'Publishing: "{msg.data}"')
        self.i += 1

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

if __name__ == '__main__':
    main()

Register the entry point and build

Add the console_scripts entry to setup.py, then build and run.

# In setup.py, add to entry_points:
entry_points={
    'console_scripts': [
        'my_publisher = my_robot_pkg.my_node:main',
    ],
},

# Build and run
cd ~/ros2_ws
colcon build --packages-select my_robot_pkg
source install/setup.bash
ros2 run my_robot_pkg my_publisher

4. Docker & VS Code DevContainer

Containerize your ROS 2 development for reproducible, shareable environments.

Dockerfile for ROS 2 development

Use the official OSRF ROS 2 base image for reproducible environments.

FROM osrf/ros:jazzy-desktop

# Install development dependencies
RUN apt-get update && apt-get install -y \
  python3-colcon-common-extensions \
  python3-rosdep \
  ros-jazzy-nav2-bringup \
  ros-jazzy-slam-toolbox \
  && rm -rf /var/lib/apt/lists/*

# Initialize rosdep
RUN rosdep update

# Source ROS 2 in all shells
RUN echo "source /opt/ros/jazzy/setup.bash" >> /root/.bashrc

WORKDIR /ros2_ws
COPY src/ src/
RUN bash -c "source /opt/ros/jazzy/setup.bash && \
  rosdep install --from-paths src --ignore-src -r -y && \
  colcon build"

.devcontainer/devcontainer.json for VS Code

Open your ROS 2 project in a VS Code DevContainer for one-command setup.

{
  "name": "ROS 2 Jazzy Dev",
  "image": "osrf/ros:jazzy-desktop",
  "customizations": {
    "vscode": {
      "extensions": [
        "ms-python.python",
        "ms-iot.vscode-ros",
        "ms-vscode-remote.remote-containers"
      ],
      "settings": {
        "python.pythonPath": "/usr/bin/python3",
        "ros.distro": "jazzy"
      }
    }
  },
  "postCreateCommand": "rosdep update && pip install pytest-ros",
  "runArgs": [
    "--network=host",
    "--pid=host",
    "--ipc=host"
  ],
  "mounts": [
    "source=/tmp/.X11-unix,target=/tmp/.X11-unix,type=bind"
  ],
  "containerEnv": {
    "DISPLAY": "${localEnv:DISPLAY}",
    "ROS_DOMAIN_ID": "0"
  }
}

💡 --network=host is required for DDS discovery across containers and the host machine.

5. Troubleshooting

ros2: command not found

Cause: ROS 2 environment not sourced in current terminal.

Fix: Run: source /opt/ros/jazzy/setup.bash — or add it to ~/.bashrc

No nodes found / ros2 topic list is empty

Cause: ROS_DOMAIN_ID mismatch between publisher and subscriber.

Fix: Export the same domain: export ROS_DOMAIN_ID=0 in both terminals.

colcon build fails with 'package not found'

Cause: rosdep not initialized or dependencies missing.

Fix: Run: rosdep install --from-paths src --ignore-src -r -y

Nav2 crashes with 'transform timeout'

Cause: Missing or delayed TF transforms — usually map→odom→base_link chain.

Fix: Check: ros2 run tf2_tools view_frames.py — ensure transform chain is continuous.

RViz2 shows blank map / no lidar scan

Cause: Sensor topic names or frame IDs don't match RViz2 configuration.

Fix: ros2 topic list to find actual topic names, then update Fixed Frame and topic subscriptions in RViz2.