In this guide
You have built Arduino robots: one sketch, sensors wired directly, everything in a single loop. It works — until the robot needs a camera, a lidar, path planning, and a web dashboard simultaneously. The single-sketch approach collapses under that complexity.
ROS2 (Robot Operating System 2) is how the robotics industry structures complex robots: as networks of small programs passing messages. It has a learning curve, but it is the single most employable robotics skill you can pick up as a student. This guide gives you the mental model and a working first project.
What ROS2 actually is
Despite the name, ROS2 is not an operating system — it runs on Ubuntu (and others). It is middleware: a framework providing:
- Communication infrastructure — standardized ways for robot software components to talk
- Tools — visualization (RViz), logging, simulation (Gazebo), debugging
- Libraries — navigation, mapping, motion planning, perception — thousands of community packages
ROS2 is the successor to ROS1, rebuilt for production: real-time support, multi-robot systems, and no single master process that can crash everything (ROS1's infamous roscore).
Note: ROS1 is legacy. Every new project, tutorial, and job posting means ROS2 (currently the actively maintained distributions). Do not start with ROS1 in 2026.
The computation graph: nodes, topics, services
ROS2 programs are nodes — small processes each doing one job. They communicate three ways:
| Pattern | Style | Use for |
|---|---|---|
| Topics | Publish/subscribe, many-to-many, continuous | Sensor streams (camera images, lidar scans, odometry) |
| Services | Request/response, one-to-one | Occasional actions ("take a picture", "reset odometry") |
| Actions | Long-running goals with feedback | Navigation ("go to x,y" with progress updates, cancellable) |
[ camera_node ] --publishes-->/camera/image-->--subscribes--> [ vision_node ]
[ lidar_node ] --publishes-->/scan------------>--subscribes--> [ slam_node ]
[ slam_node ] --publishes-->/map------------->--subscribes--> [ nav_node ]
Each node is independently understandable, testable, and replaceable. Your Arduino sketch did all of this in one tangled loop; ROS2 gives each job its own process and a typed contract between them.
Messages are typed. A topic carries a defined message type (sensor_msgs/Image, sensor_msgs/LaserScan). Publishers and subscribers agree on the type — mismatches are caught, not silently misinterpreted.
Your first ROS2 workspace
Install ROS2 on Ubuntu (the documented path — use a VM or dual boot if you are on Windows), then:
source /opt/ros/<distro>/setup.bash
That source line loads the ROS2 environment — put it in your ~/.bashrc or you will retype it forever. Key commands to learn first:
ros2 topic list # what topics exist right now
ros2 topic echo /scan # watch messages flowing on a topic
ros2 node list # running nodes
ros2 service list # available services
ros2 run <pkg> <node> # run a single node
ros2 topic echo is your oscilloscope for robot software — when data is not flowing, this is where you look first.
Writing a node (Python)
ROS2's Python client library is rclpy. A minimal publisher:
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class Talker(Node):
def __init__(self):
super().__init__('talker')
self.publisher = self.create_publisher(String, 'chatter', 10)
self.timer = self.create_timer(1.0, self.publish_message)
self.count = 0
def publish_message(self):
msg = String()
msg.data = 'Hello ' + str(self.count)
self.publisher.publish(msg)
self.count += 1
def main():
rclpy.init()
node = Talker()
rclpy.spin(node) # keep the node alive, processing callbacks
node.destroy_node()
rclpy.shutdown()
The structure of every node: initialize, create publishers/subscribers/timers, spin to process callbacks until shutdown. Learn this skeleton and every ROS2 tutorial becomes readable.
Packages, workspaces, and colcon
ROS2 code lives in packages inside a workspace (~/ros2_ws/src/), built with colcon:
cd ~/ros2_ws
colcon build --packages-select my_package
source install/setup.bash
The ritual after building: source the workspace (source install/setup.bash) in every new terminal, or your new nodes are invisible. Beginners lose hours to forgetting this — when ros2 run says "package not found," sourcing is the first thing to check.
The tools that make it click
- RViz — 3D visualization: see lidar scans, robot models, planned paths. "My robot thinks X" becomes visible.
- Gazebo — physics simulation. Test your navigation stack on a virtual robot before the physical one drives into a wall.
- rqt — GUI tools including the computation-graph viewer (
rqt_graph), which draws your nodes and topics live. Run it early and often — it makes the abstract graph concrete. - ros2 bag — record topic data to files, replay it later. Record once on the real robot, develop perception code on your laptop against the recording.
Simulation-first: the student superpower
You do not need a physical robot to learn ROS2 deeply. The standard student path:
- Simulate a robot in Gazebo (TurtleBot3 is the canonical beginner platform).
- Build mapping and navigation in simulation.
- Only then move to hardware.
Simulation removes the two scarcest student resources — hardware access and debugging time. A bug in simulation costs seconds; the same bug on hardware costs a crashed robot.
Launch files: starting the whole system
Real robots run dozens of nodes. You do not start them in dozens of terminals — you write a launch file:
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='my_robot',
executable='camera_node',
name='camera',
parameters=[{'fps': 30}],
),
Node(
package='my_robot',
executable='motor_node',
name='motors',
parameters=[{'max_speed': 0.5}],
),
])
Run it with ros2 launch my_robot robot.launch.py — one command, whole system, parameters set declaratively instead of hardcoded. Launch files also handle ordering, remapping topic names, and including other launch files, so your "start the robot" procedure is version-controlled documentation rather than tribal knowledge. Any multi-node project should have one before its first demo.
Common mistakes
- Forgetting to source.
setup.bashfor ROS2,install/setup.bashfor your workspace — every terminal. Automate it in.bashrc. - One giant node. A node that reads sensors, plans paths, and drives motors is an Arduino sketch wearing a ROS2 costume. Split by responsibility.
- Topics for request/response. Need an answer back? That is a service, not a topic. Topics are for continuous streams.
- No message-type discipline. Publishing custom blobs instead of standard messages (
sensor_msgs/*,geometry_msgs/*) locks you out of the entire ecosystem of tools that understand standard types. - Skipping simulation. Going straight to hardware multiplies every bug's cost.
- Hardcoding topic names and magic numbers. Use ROS2 parameters (
declare_parameter, launch files) so behavior is configurable without recompiling.
A realistic first project path
- ROS2 installed; talker/listener tutorial running
- Custom message types; a two-node system you designed
- TurtleBot3 in Gazebo driving with keyboard teleop
- SLAM in simulation (see SLAM Explained Simply)
- Autonomous navigation to goals in simulation
- Same stack on a physical robot (borrowed, lab-owned, or budget-built)
Where to go from here
- Mapping with your lidar: SLAM Explained Simply.
- Robot arms in ROS2 need Inverse Kinematics for Robot Arms.
- Real-time constraints on microcontrollers: FreeRTOS basics on ESP32.
- Talking to sensors: I2C vs SPI vs UART explained.
- Choosing actuators: Servo vs stepper motor selection.
- More robotics topics in the IoT & Embedded branch hub.