ROS 2 (Robot Operating System 2) is the foundation of modern robotics. This guide takes you from zero to your first working robot program — covering installation, core concepts, and real code you can run today.
ROS 2 Humble runs best on Ubuntu 22.04 (Jammy Jellyfish). If you're on Windows, install WSL2 with Ubuntu 22.04, or use a VM. macOS users can use Docker (see note).
Configure your system locale and add the official ROS 2 apt repository.
# Set UTF-8 locale 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 and repo 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 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
The 'desktop' meta-package includes RViz2, demo nodes, and all core libraries. Use 'ros-base' for headless robots.
sudo apt update && sudo apt upgrade -y sudo apt install ros-humble-desktop -y sudo apt install python3-rosdep python3-colcon-common-extensions -y # Initialize rosdep sudo rosdep init rosdep update
Add the ROS 2 setup script to your .bashrc so it loads in every terminal, then verify with the talker/listener demo.
# Add to ~/.bashrc (run once) echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc source ~/.bashrc # Test: open 2 terminals and run: # Terminal 1: ros2 run demo_nodes_cpp talker # Terminal 2: ros2 run demo_nodes_py listener # You should see: [INFO] I heard: [Hello World: N]
ROS 2 has six core communication primitives. Understanding them unlocks everything else.
A node is a single executable process that performs a specific task. A robot system is made of many nodes communicating with each other.
# List running nodes ros2 node list # Get info about a node ros2 node info /talker
Topics implement a publish/subscribe pattern. Nodes publish messages to a topic; any number of nodes can subscribe to receive them.
# List active topics
ros2 topic list
# Echo messages on a topic
ros2 topic echo /chatter
# Publish manually
ros2 topic pub /chatter std_msgs/msg/String '{"data": "Hello from terminal"}'Services implement request/response. One node calls a service; the server node processes and returns a response synchronously.
# List services
ros2 service list
# Call a service
ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 5, b: 3}"
# Response: sum: 8Actions extend services with feedback during execution and the ability to cancel. Perfect for long-running tasks like navigation.
# List action servers
ros2 action list
# Send a Fibonacci action goal
ros2 action send_goal /fibonacci action_tutorials_interfaces/action/Fibonacci "{order: 10}" --feedbackParameters let you configure node behavior at runtime without recompiling. They're stored per-node and type-safe.
# List parameters for a node ros2 param list /my_node # Get a parameter value ros2 param get /my_node robot_name # Set a parameter at runtime ros2 param set /my_node max_speed 1.5
Launch files start multiple nodes with parameters in one command. Written in Python (ROS 2) for full programmability.
# my_robot_launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='my_robot',
executable='robot_controller',
parameters=[{'max_speed': 1.0}]
),
Node(
package='my_robot',
executable='lidar_processor',
),
])Build a complete publisher/subscriber pair in Python. Copy and paste each block — it will run.
# Create workspace mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src # Create a Python package ros2 pkg create --build-type ament_python --node-name my_node my_first_robot # Build cd ~/ros2_ws && colcon build source install/setup.bash
# ~/ros2_ws/src/my_first_robot/my_first_robot/publisher.py
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class RobotPublisher(Node):
def __init__(self):
super().__init__('robot_publisher')
self.pub = self.create_publisher(String, 'robot_status', 10)
self.timer = self.create_timer(1.0, self.timer_callback)
self.count = 0
def timer_callback(self):
msg = String()
msg.data = f'Robot status: cycle {self.count}'
self.pub.publish(msg)
self.get_logger().info(f'Publishing: {msg.data}')
self.count += 1
def main(args=None):
rclpy.init(args=args)
node = RobotPublisher()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()# ~/ros2_ws/src/my_first_robot/my_first_robot/subscriber.py
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class RobotSubscriber(Node):
def __init__(self):
super().__init__('robot_subscriber')
self.sub = self.create_subscription(
String, 'robot_status', self.callback, 10)
def callback(self, msg):
self.get_logger().info(f'Received: {msg.data}')
def main(args=None):
rclpy.init(args=args)
node = RobotSubscriber()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()# In setup.py, add entry_points:
entry_points={
'console_scripts': [
'publisher = my_first_robot.publisher:main',
'subscriber = my_first_robot.subscriber:main',
],
},
# Rebuild and run
cd ~/ros2_ws && colcon build --symlink-install
source install/setup.bash
# Terminal 1:
ros2 run my_first_robot publisher
# Terminal 2:
ros2 run my_first_robot subscriber# Node management
ros2 node list # list all running nodes
ros2 node info /node_name # show node details
# Topics
ros2 topic list # list all topics
ros2 topic echo /topic_name # print messages
ros2 topic hz /topic_name # check publish rate
ros2 topic pub /topic std_msgs/msg/String '{"data":"hi"}' -1
# Services
ros2 service list # list all services
ros2 service call /service example_interfaces/srv/AddTwoInts "{a: 1, b: 2}"
# Parameters
ros2 param list /node_name # list params
ros2 param get /node_name param # get value
ros2 param set /node_name param value # set value
ros2 param dump /node_name # dump all to YAML
# Packages
ros2 pkg list # list installed packages
ros2 pkg prefix my_package # find package path
# Build (in workspace root)
colcon build # build all packages
colcon build --packages-select my_pkg # build one package
colcon build --symlink-install # dev mode (no rebuild for Python)
# Launch
ros2 launch my_package my_launch.py # run a launch fileLearn how ROS 2 tracks coordinate frames for every part of your robot (base_link → wheel → camera → world).
Define your robot's physical structure in URDF XML. Visualize it in RViz2 with the robot_state_publisher.
The standard robotics visualization tool. Add laser scan, camera, TF, and marker displays to debug your robot.
Simulate your robot in a physics engine. Test Nav2, SLAM, and manipulation before touching real hardware.
The standard ROS 2 navigation stack. Handles path planning, obstacle avoidance, and goal execution.
Simultaneous Localization and Mapping. Build a map while your robot navigates an unknown environment.