Your first 20 minutes with ROS 2
Install ROS 2, launch turtlesim, publish a velocity message, and understand the three primitives that underpin every ROS program. No robot required.
ROS is the air that robotics people breathe. It's also the part every beginner bounces off of first. Let's fix that in 20 minutes. No robot required — we'll drive a simulated turtle with arrow keys.
What ROS 2 is, in one paragraph
ROS 2 is a middleware. It lets many small programs (nodes) on one or many computers talk to each other through named channels (topics) with strongly-typed messages. That's it. Every fancy robotics package — Nav2, MoveIt, Gazebo bridges — is built on those three primitives. Learn the primitives first, the packages come for free.
What you'll have at the end
A running ROS 2 install, turtlesim on your screen, and you driving a cartoon turtle with the arrow keys by publishing velocity messages over a topic. Not impressive — but everything after this uses the same three ideas.
Install (pick one)
Linux (Ubuntu 22.04 / 24.04) — native
sudo apt update && sudo apt install -y curl gnupg lsb-release
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 $(lsb_release -cs) main" \
| sudo tee /etc/apt/sources.list.d/ros2.list
sudo apt update && sudo apt install -y ros-jazzy-desktop
macOS or Windows — Docker or devcontainer
Running ROS 2 natively on macOS or Windows is painful. In 2026, use a container. The osrf/ros:jazzy-desktop image is the shortest path:
docker run -it --rm \
-e DISPLAY=$DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix \
osrf/ros:jazzy-desktop bash
On macOS you'll also need XQuartz; on Windows 11, WSL 2 with WSLg handles X11 automatically.
The three primitives
- Node. A process that does one thing. A camera driver is a node. A motor controller is a node. Your code will be a node.
- Topic. A named pub/sub channel between nodes.
/camera/image_rawcarries camera frames./cmd_velcarries velocity commands. Any node can publish or subscribe. - Message. The strongly-typed payload on a topic.
geometry_msgs/Twistfor velocity,sensor_msgs/Imagefor frames,std_msgs/Stringwhen you're being lazy.
Services and actions (remote procedure calls and long-running goals) are variations of the same idea. Master topics first.
Drive the turtle
Terminal 1:
source /opt/ros/jazzy/setup.bash
ros2 run turtlesim turtlesim_node
A window pops up with a cartoon turtle in the middle.
Terminal 2:
source /opt/ros/jazzy/setup.bash
ros2 run turtlesim turtle_teleop_key
Click into this terminal and press the arrow keys. The turtle moves. Congratulations — you've driven your first ROS 2 robot.
See the actual traffic
Terminal 3:
source /opt/ros/jazzy/setup.bash
ros2 topic list
ros2 topic echo /turtle1/cmd_vel
Every arrow press emits one geometry_msgs/Twist message on /turtle1/cmd_vel. The teleop node is the publisher. The simulator node is the subscriber. That's it. That's every ROS program you will ever read.
Write your own publisher (bonus)
In a new file circle.py:
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
class CircleDriver(Node):
def __init__(self):
super().__init__('circle_driver')
self.pub = self.create_publisher(Twist, '/turtle1/cmd_vel', 10)
self.timer = self.create_timer(0.1, self.tick)
def tick(self):
msg = Twist()
msg.linear.x = 1.0
msg.angular.z = 1.0
self.pub.publish(msg)
def main():
rclpy.init()
rclpy.spin(CircleDriver())
if __name__ == '__main__':
main()
Stop the teleop node, run python3 circle.py, and the turtle draws circles. You've now built a node.
Troubleshooting the top three errors
- "command not found: ros2" — you forgot
source /opt/ros/jazzy/setup.bash. Add it to your~/.bashrconce you're committed. - turtlesim window doesn't open in Docker — X11 forwarding isn't set up. On Linux,
xhost +local:docker; on macOS, start XQuartz and check "Allow connections from network clients." - No topics visible between machines — ROS 2 discovery is on by default but firewalls (and some VPNs) block the multicast it uses. Set
ROS_LOCALHOST_ONLY=1to stay on one machine, or switch to the Zenoh RMW for multi-host setups.
What comes next
The next four lessons in this track are: nodes, topics, messages in depth; writing a Python publisher/subscriber pair; services vs actions vs topics; and launch files for starting 20 nodes at once. If you want a full book, the official ROS 2 Jazzy tutorials are excellent — ours cut straight to what a roboticist needs, theirs cover every corner case.
Comments
Sign in to post a comment.