Where you are. You have picked a track. Everything from here is shared across all three, starting with the piece of the industry you have so far managed to avoid completely.
Nine months, one process
Everything you have built runs inside a single Python program. Read the camera, call the policy, write six joint angles down a serial bus, loop. One clock. One language. One place to put a breakpoint.
Now open the crate a commercial robot arrives in.
Inside there is an arm driver written by the arm’s manufacturer, a depth-camera driver written by the camera’s manufacturer, a battery and thermal monitor written by the integrator, a safety supervisor that somebody had to get certified, and a wheelbase controller from 2019 whose author left the company. Five programs, four organisations, two languages, written years apart. None of them import each other. None of them can.
They ship together anyway, and they work, because every one of them was written against the same agreement: named channels, typed messages, and a way for processes to find each other on a network without anyone configuring anything.
That agreement is the thing you have been skipping.
The idea in one paragraph
ROS 2 is not a framework you write your robot inside. It is four separate things wearing one name: a peer-to-peer message bus, a build and packaging convention, an interface definition language for messages, and an archive of a few thousand hardware drivers other people already wrote. You are learning it for two reasons, and neither one is that it will make your own work faster. The first is that industry deployment assumes it, so the moment your code has to sit next to somebody else’s driver, this is the socket. The second is that interviews assume it, and the questions are consistent enough that you can prepare for them precisely. Learn it as a compatibility layer, not as a runtime. Then learn which parts of it are current, because a large fraction of what you will find written about ROS is about a version that is dead.
Wider than the screen; scroll it sideways.
The genuine minimum
Two tiers. The first is one or two weeks of evenings, and it is the part that is genuinely not optional.
| Concept | Where you meet it | Why it is on the list |
|---|---|---|
| Workspace and build | colcon build, then source install/setup.bash | Nothing works before you source, and knowing why is a real interview filter |
| Nodes and topics | rclpy publisher and subscriber; ros2 topic echo, hz, info | The whole model, in about forty lines |
| Interfaces | .msg, .srv, .action files; ros2 interface show | Typed contracts between processes you did not write |
| Quality of service | reliability, durability, history | The most common silent failure in the system |
| Parameters | ros2 param, YAML parameter files | How every real node is configured |
| Launch files | Python launch, or XML launch, both current | Composing a multi-node system with remaps and namespaces |
| tf2 | tf2_echo, view_frames | The frame maths you already did, with an API and a clock attached |
| rosbag2 | ros2 bag record and play | Recordings, which for you are datasets |
| Debugging | ros2 doctor, rqt_graph, ros2 topic hz and delay | Because nothing tells you when it is wrong |
Two of those rows are cheap for you specifically. The tf2 library is the transform tree from the kinematics module with time added: every frame relationship is stamped, and you ask for the relationship as of a moment rather than now. You already own the maths; what is new is the buffering and the interpolation. And rosbag2 is a recording format, which is the subject of the next lesson.
Sourcing deserves one sentence of explanation rather than a shrug: source install/setup.bash edits environment variables in your current shell so that Python can import your packages, the CLI can find your executables, and message types resolve. It is not a build step. It is why a new terminal breaks everything, forever, in every ROS installation on earth.
The failure that produces no error
Every publisher offers a contract and every subscriber requests one. If the offer does not satisfy the request, they simply do not connect. No exception, no warning on either side, and the topic still appears in ros2 topic list because the publisher genuinely is publishing.
Wider than the screen; scroll it sideways.
The second tier
About another week, and this is where interviews go when they want to know whether you have actually used it.
Actions matter more than services. An action is a goal, a stream of feedback, a terminal result, and a cancel channel, built on top of topics and services. You have designed this exact thing before under a different name. The whole public interface of the main open-source navigation stack is actions, so if you are wiring a planner over a robot, this is the surface you meet.
Lifecycle nodes are managed nodes with explicit states: unconfigured, inactive, active, finalized, with transitions you drive from outside. They exist because a robot that brings up twelve processes in an arbitrary order will hurt someone. Know the state names.
Executors and callback groups are where the good question lives.
Wider than the screen; scroll it sideways.
Two more, at vocabulary depth. Composition puts several components in one process so they can pass messages without copying, which matters enormously for camera pipelines. And RMW is the pluggable middleware layer: a DDS implementation is the default, an alternative DDS is common, and a Zenoh-based option has been a supported tier-one middleware since the 2025 release without being the default anywhere. One paragraph of awareness, not a project.
Why your own stack skips all of this
Because it should. A learned policy takes images and joint states and emits joint commands at 30 to 50 Hz. There is no planner in that loop, no motion planning library, and often nothing that would benefit from being split into six processes with a discovery protocol between them. Adding a bus to a single-process control loop buys latency and a deployment problem.
So hold both. Your daily driver is a Python process. The bus is how that process gets adopted by someone whose robot already has eleven other processes on it, and how you talk about robots with people who have only ever worked that way.
What is legacy, plainly
Half the ROS material online describes a system that is gone. This table is the fastest money you will make in this module.
| Dead or dying | The current thing | Since |
|---|---|---|
Everything ROS 1: rospy, catkin, roslaunch, nodelets, .bag files | ROS 2 equivalents throughout | Final ROS 1 release went end of life in May 2025 |
| Gazebo Classic | Modern Gazebo: Harmonic pairs with the current teaching distro, Jetty with the newest | Classic went end of life in January 2025 |
| The 2025 non-long-term-support distro | A long-term-support distro, always | It goes end of life in November 2026 |
| rosbag2 sqlite3 storage | MCAP as the default container | See the next lesson |
Most of rqt beyond rqt_graph | Foxglove or Rerun | Gradually, over the last few years |
| Hand-tuning DDS profiles | Knowing the concept exists | It is a specialist’s job, not a learner’s |
Distributions are named alphabetically and released each May. Two long-term-support ones matter today.
| Distro | Released | End of life | Ubuntu | Use it? |
|---|---|---|---|---|
| Humble | May 2022 | May 2027 | 22.04 | Largest installed base, but it expires next year |
| Jazzy | May 2024 | May 2029 | 24.04 | Teach and learn on this one |
| Kilted | May 2025 | November 2026 | 24.04 | No. Non-LTS and nearly gone |
| Lyrical | May 2026 | May 2031 | 26.04 | Where the industry moves through 2027 |
Learn on Jazzy. It is supported into 2029, it is the version named in current job postings, and every significant package has a stable release on it. The newest long-term-support distro is technically better, and one of its additions will interest you: a Python node class that lets you await ordinary asyncio operations inside callbacks, which removes a whole category of the deadlock above. But its ecosystem is a few months old, and a package having a release on it is not the same as that release being the one everyone runs. Concepts are identical across distros. Only package names and dates change.
Where it will run, honestly
There are no official macOS binaries. The platform is a source-build tier and has been fragile for years. Three approaches work, and you should pick by what you need to see.
| Approach | What you get | What it costs |
|---|---|---|
Conda-based packages via pixi | Native Apple silicon, no container, distros through the newest | Never source an apt ROS environment alongside it; the Python paths collide |
| Docker with arm64 images | Runs natively, clean for nodes, topics and builds | Graphical tools over X11 are slow and awkward |
| A Linux virtual machine | Everything works, including the 3D tools | Heaviest option, and it wants real RAM |
One stack, chosen for you
Two large frameworks sit on top of ROS 2: one for navigation, one for arm motion planning. Learn the navigation one.
The reason is what each one teaches, not which is healthier. Both are alive: checked against the ROS distribution index on 9 August 2026, both the navigation stack and the motion planning stack have current releases on the two newest distros. What differs is what a week with each buys you.
Navigation teaches more transferable architecture: behaviour trees, lifecycle nodes, action servers, layered costmaps and plugin-based planners. And it runs end to end in simulation on a laptop, whereas motion planning without an arm in front of you is mostly a configuration exercise.
That said, you have an arm and you are heading toward manipulation, so spend an afternoon on the vocabulary of the motion planning stack: the central planning node, the planning scene, the servo component for streaming velocity commands, and the setup assistant that generates the configuration. Enough to hold a conversation. Be clear-eyed that the learning-first labs mostly bypass sampling-based planners altogether, since a policy emits joint commands directly at 30 to 50 Hz.
One more honesty, on language. Platform and infrastructure job postings say C++17 or C++20 and they mean it. Python-only closes the robotics platform engineer door. It does not close the robot learning engineer door, or the data and simulation infrastructure doors, which is where your background points anyway. Decide that deliberately rather than finding out in a screen.
Check yourself
1. Your publisher is running, ros2 topic list shows the topic, and your subscriber’s callback never fires. What do you check first, and why is there no error message?
Quality of service compatibility on both ends, with ros2 topic info --verbose. Publishers offer a contract and subscribers request one; if the offer cannot satisfy the request the two are simply never matched, and neither side considers that an error, because from the publisher’s point of view it is publishing correctly and from the subscriber’s point of view no compatible publisher exists. The classic pair is a sensor driver offering best-effort against a hand-written subscriber requesting reliable. Durability is the other half: a late-joining subscriber gets nothing unless the publisher is transient-local.
2. Why does calling a service from inside a callback deadlock on the default executor, and what are the two fixes?
The response arrives and is placed in the executor’s queue. The only thread that drains that queue is the executor, which is currently inside your callback waiting for the response, so it never gets processed. It is the same shape as blocking on a task from inside a handler that the same event loop has to run in order to complete it. Fix one: do not block, and handle the response in a separate callback. Fix two: put the nested work in a re-entrant or separate callback group and run a multi-threaded executor.
3. Someone hands you a tutorial that uses rospy, catkin and roslaunch. What does that tell you, and what else in the same repository is suspect?
It is ROS 1, whose final release went end of life in May 2025, so the tutorial is at least a version behind and possibly many years old. Everything around it is suspect: it will likely also use Gazebo Classic, which went end of life in January 2025, sqlite-backed bags rather than the current default container, and rqt tooling that has largely been replaced by browser and notebook viewers. The concepts still transfer; none of the commands do.
4. Why does the learning-first stack bypass ROS 2, and why do you learn it anyway?
Because a learned policy is one process consuming images and joint states and emitting joint commands at 30 to 50 Hz. There is no planner in that loop and no benefit to splitting it into processes with a discovery protocol between them; adding a bus buys latency and a deployment problem. You learn it because deployment and hiring both assume it. The moment your code sits next to a driver somebody else wrote, this is the socket, and the interview questions come from this vocabulary regardless of what your own robot runs.
5. Which distribution do you learn on today, and what is the argument against the newest one?
Jazzy, released May 2024 and supported to May 2029. It is what current job postings name and every significant package has a stable release on it. The newest long-term-support release, from May 2026, is technically better and supported to 2031, but its ecosystem is only months old and thinner than Jazzy’s. Since the concepts are identical across distributions and only package names and dates change, there is no learning benefit that offsets a thin package ecosystem.
6. What is the one-sentence honest position on ROS 2 that this lesson wants you to hold?
You are learning it as an interface to the industry, not as your daily driver. Your own stack stays a single fast Python process; ROS 2 is how that process is adopted by a robot that already runs eleven others, and how you hold a conversation with people who have only ever built that way.
Do this
Two evenings. The goal is one running graph and one deliberately broken one, not a project.
1. Get an environment, then stop tuning it. Use the conda-based packages through pixi on Apple silicon, or an arm64 Docker image, and follow whichever install page you chose rather than any instructions written down here; they change more often than lessons do. Success is ros2 doctor running and ros2 run demo_nodes_py talker printing. Time-box this to ninety minutes. If it fights you, switch approach rather than debugging it.
2. Run the graph and look at it from outside. With the talker running, in other terminals:
ros2 node list
ros2 topic list
ros2 topic info /chatter --verbose
ros2 topic echo /chatter
ros2 topic hz /chatter
Read the verbose output properly. The reliability, durability and history fields it prints are the contract from the figure above.
3. Break it on purpose. Publish and subscribe on the same topic with deliberately incompatible settings, using the quality-of-service flags on ros2 topic pub and ros2 topic echo. Check --help on your distro for the exact flag spelling. Confirm two things with your own eyes: no message arrives, and nothing anywhere prints an error. Then fix it by relaxing the subscriber. This is the ten minutes that makes the interview answer yours rather than remembered.
4. Record something and read it back. ros2 bag record /chatter for a few seconds, then ros2 bag info and ros2 bag play. Notice which storage format it wrote by default. Keep that recording; the next lesson opens it in three different tools.
5. Write down the deadlock. In notes/07-ros2.md, draw the executor deadlock from memory and write the two fixes in your own words. Two minutes, and it is the thing you will actually be asked.
What you can now do
You can say what ROS 2 is in four parts rather than as one vague framework, name the concepts a working engineer is assumed to know and skip the rest without anxiety, diagnose the quality-of-service mismatch that produces no error, explain the single-threaded executor deadlock as the event-loop bug you already know, pick a distribution and a platform for the machine you actually own, and recognise ROS 1, Gazebo Classic and non-supported distributions on sight so that a decade of stale tutorials stops costing you time.