Sep 5, 2026 · ros2 · troubleshooting · learning-curve · robotics-middleware
Why Is ROS 2 So Hard? The Six Things That Trip Newcomers Up
ROS 2 is hard because six setup systems must all be right before a robot moves. Learn them if you need the ecosystem, step down to something smaller if not.
ROS 2 is hard for a real reason: six separate systems must be correct before anything moves, and alternatives trade ecosystem for fewer of them. Five of the six are configuration rather than robotics, so the difficulty is front-loaded and mostly disappears once learned. If your robot leans on borrowed packages, learning them is the cheaper path; if not, a smaller middleware such as HORUS removes most of them. The rest of this post is for someone who has already fought the tutorials and wants to know which part is worth learning and which part to route around.
You did the tutorial. The talker and the listener worked, so you wrote your own node, and now nothing happens. The build succeeded. The program starts. The topic list shows your topic. The callback never fires, and there is no error anywhere — not in the terminal, not in a log, not in the exit code. You add a print statement and the print statement does not appear either, which somehow makes it worse.
Then it works, and you do not know why. You reboot and it stops. A forum thread says to set an environment variable you have never heard of, another says to change a delivery setting on your subscriber, and a third blames your virtual machine's network adapter. Every answer is plausible and none explains the others.
The feeling underneath it is not confusion about robots. You can write a control loop. You know what a message is. What you cannot do is tell which of the layers between your two programs decided to stay silent, and that is a skill nobody teaches directly, because every tutorial shows the version where it already works.
Why is ROS 2 so hard for people who are new to it?
ROS 2 is hard because being correct about six unrelated things is required before the robot does anything at all. Each of the six is an ordinary engineering topic on its own — a build system, a discovery mechanism, a set of delivery rules, a start-up description, a callback model, and version compatibility. Taken one at a time, over a few weeks, none is difficult. They arrive simultaneously, on day one, in a project where you also do not yet know whether your motor wiring is right. Worse, most of them fail silently. A build system that fails loudly is a mild annoyance; a delivery-rule mismatch that quietly declines to connect two working programs produces no message at all, so a beginner searches their own code for a bug that is not there. The skill ROS 2 actually demands early is not programming. It is layered diagnosis: knowing whether to suspect your shell, your network, your settings or your logic, and knowing how to ask each layer what it thinks is happening.
What is ROS 2 actually doing behind a publisher and a subscriber?
Behind two lines of publisher code sits a distributed system that assumes your robot might be a network of computers. When a node starts, it announces itself so other nodes can find it without a central registry, which means the discovery process depends on your network interfaces even when both programs are on one desktop. When you publish, the message is converted into a defined wire format and handed to a transport layer that follows per-connection rules about whether old messages are kept, whether delivery is guaranteed, and how deep a queue may grow. On the other side, an executor decides which callback runs, in which order, and on which thread. Every one of those pieces exists because someone had a real requirement: multiple machines, replaceable transport vendors, predictable timing under load. None of them exists because a beginner needed it. That is the honest source of the difficulty — you are paying, on your first afternoon, for a design meant to survive a fleet of robots and several vendors.
What are the six things that trip newcomers up?
Six specific mechanisms account for most first-month misery, and naming them makes each one ordinary:
- The workspace and the build step. Code must be built, then the install area added to the current shell. Forget the second half and a correctly built package is invisible.
- Discovery. Nodes find each other over the network, so containers, virtual machines, firewalls or a shared identifier on an office LAN all change who can see whom.
- Delivery settings. Publishers and subscribers each declare how messages should be handled. Incompatible declarations do not connect and do not complain.
- Launch descriptions and parameters. Starting the robot becomes its own small language, with its own file formats and failure modes.
- Executors and callbacks. Callbacks share a thread by default, so one slow callback quietly holds up the others, and the symptom looks like a hardware fault.
- Version drift. Tutorials are written for one distribution and one operating system release, and the package you need was built for another.
Only the fifth is really about robots. The rest are the price of a system designed for many machines and many contributors.
What are your options once the setup keeps fighting you?
You have four real options, and quitting robotics is not one of them. You can stay on ROS 2 and learn the six deliberately, which is the right call whenever borrowed packages are the point of your project. You can stay on ROS 2 but remove the environment variables from the equation by working inside a prepared container image, which deletes two of the six for the cost of learning containers. You can split the difference, keeping ROS 2 for the ecosystem while your timing-sensitive loop lives in code you own. Or you can step down to a smaller middleware such as HORUS, an open-source real-time robotics middleware for Rust, Python and C++ where all three languages share the same shared-memory ring buffers, so messages between processes on one machine are not serialised — which removes discovery, delivery negotiation and the build ceremony, and also removes the ecosystem that made ROS 2 attractive.
| Option | Who it is for | What it assumes you know | When to pick it | When not to |
|---|---|---|---|---|
| Learn ROS 2 properly | Anyone staying in robotics for years | Linux shells, build tools, basic networking | Borrowed drivers, mapping or navigation are the project | You have a deadline this month |
| ROS 2 in a prepared container | Learners losing days to environment drift | Container basics and file mounting | The same setup must work on several machines | Your hardware access fights the container |
| ROS 2 plus your own timed loop | Teams whose robot stutters under load | Both ROS 2 and your own scheduling | The ecosystem is needed but the loop must hold rhythm | Nobody on the team owns the seam |
| HORUS | Mixed-language builders on a single machine | Your message types and how your loops are scheduled | Python, C++ and Rust parts share data on one box | Borrowed packages are the value and would need porting |
| Single program, no middleware | One builder, one board, one behaviour | Basic Python or C++ and your sensor's driver | The robot is one sensor, one decision, one actuator | Two parts need separate rhythms |
| Microcontroller firmware | Builders whose robot is a fixed behaviour | Embedded C or MicroPython, and your board's pins | No camera, no map, no desktop | You want vision, logging or replay |
What should you do if you are learning robotics on your own?
Learn the six in the order they will break, and do not try to understand the whole system first. A solo learner has no colleague to say "you forgot to source the workspace", so the surest path is breaking each layer once, on purpose, while everything else is known good. Start two terminals by hand and confirm the nodes see each other. Then change the delivery settings on one side and watch messages vanish without an error, so silence becomes a symptom you recognise instead of a mystery. Rename a package and read what the run command says. Each experiment takes minutes and buys a diagnosis you would otherwise chase for an evening. The other advice for solo learners is unfashionable but true: keep your own robot logic in plain functions that take data and return commands. If you later decide the ecosystem is not worth the tax, as described in the case for and against starting on ROS 2, the part you actually care about moves with you.
What changes when the robot has to run on a small onboard computer?
A small onboard computer makes two of the six sharper: version drift and start-up time. The board probably runs a different operating system release than your laptop, and the package that installed cleanly at your desk may have no matching build for the machine that has to carry it, which is where an evening disappears into building from source. Start-up matters too, because every node brings its own runtime and its own initialisation, and a robot that takes a long stretch to become responsive after power-on is a robot you will test less often. Discovery becomes more interesting as well: on a laptop the network was simple, and on the robot there is a wireless link, sometimes a wired one, occasionally a tethered laptop, and each one changes who can see whom. None of this is a reason to avoid ROS 2 on small hardware, which is common and works. It is a reason to do the first port before the deadline exists, not after.
What if you have a demo in three weeks and nothing works yet?
Freeze whatever partially works and stop changing foundations. Three weeks is enough to make one impressive thing happen and not enough to migrate a system while learning its replacement, so the correct move is almost always to keep the setup you have and spend the time on the demo behaviour itself. If ROS 2 is installed and two of your nodes talk, that is your platform now. Write down the exact start-up sequence, including which terminal sources what, and treat that document as part of the robot. Remove ambition instead of removing infrastructure: a robot doing one task cleanly reads better than a robot attempting three and stuttering. The one case that justifies switching mid-schedule is a hard blocker with no workaround — a driver that does not exist, or timing your current design cannot hold — and even then, switch only the piece that is blocked. After the demo, when nobody is watching, is when architecture decisions get made honestly.
What if you are fluent in Python but new to systems programming?
A Python background leaves one gap, and the gap is not ROS 2 itself: robotics quietly requires systems knowledge that web and data work never demanded. Shells and environment variables, processes and threads, network interfaces, build artefacts, permissions on device files: none of that is Python, and all of it stands between you and a moving robot. That is worth naming because it changes what to study. Time spent on tutorials for a robotics framework will not fix a gap in how shells inherit environments, and the failure will keep reappearing in new costumes. The good news is that the required amount is small and finite. Understand what sourcing a file does, what a process is and how it dies, how to see which programs are listening on a network, and how to read a stack trace from a compiled component. A weekend on those makes the whole ecosystem feel different, and it transfers to anything you build afterwards — including a node written without the usual ceremony.
Why do messages stop arriving when both nodes are clearly running?
Two programs can be alive, correct and completely unable to connect, and ROS 2 treats that state as normal rather than as an error. The usual culprits are a delivery-settings mismatch, where the subscriber asks for guarantees the publisher does not offer; a discovery failure, where the network layer never introduced the two; or a namespace or topic-name difference that puts the publisher on a topic nobody is listening to. Each of those produces exactly the same symptom: a topic list that looks right and a callback that never runs. The diagnostic order that saves the most time is to check whether the two nodes can see each other at all, then whether the connection was actually established rather than merely requested, then your own logic last. Beginners reverse that order and spend the evening reading their own code. The habit worth building is suspecting the layers between the programs before suspecting the programs.
What do you give up if you step outside ROS 2?
You give up the largest collection of ready-made robot software in existence, and that is not a small trade. Navigation and mapping you did not write, drivers for hardware you have not bought yet, a visualiser that shows what the robot believes about the world, recording and replay so a Tuesday failure can be debugged at your desk on Thursday, simulation bridges, and years of forum threads by people who hit your exact problem. You also give up the shared vocabulary: a new contributor who knows the ecosystem can read your robot immediately, and cannot read a private architecture at all. Those are heavy losses, and they are the real argument for staying, far more than any property of the transport underneath. What you get back is a system small enough to hold in your head and a start-up sequence you can explain in one sentence. Whether that trade is sensible depends entirely on how much of your robot you were always going to write yourself, and wiring up sensor fusion is a good test of that.
When is ROS 2 the better choice?
ROS 2 is the better choice whenever the valuable part of your robot is code somebody else already wrote. A mobile base that must map a building and drive to a goal belongs on ROS 2, because reproducing mapping and navigation yourself is a multi-year project you did not sign up for. An arm doing collision-aware planning belongs there too. A lab where everyone already knows the tooling belongs there, because a shared vocabulary is worth more than a smaller concept count. If your sensor's only maintained driver ships as a package, that decides it. If your system spans several computers — robot, workstation, fleet — ROS 2 was designed for exactly that and has been proven across it. HORUS is not the answer for any of those projects, and choosing it there means rebuilding, badly, what an ecosystem already gives you. The six difficulties are a one-time cost. An ecosystem you have to recreate is a permanent one.
Is ROS 2 hard because it was designed badly?
No, and here is why: nearly every awkward part is the visible price of a requirement someone genuinely had. Discovery over the network feels absurd on one desktop, and it is what lets a robot and a workstation find each other with no configured address. Delivery settings feel like a trap, and they are what lets a control message and a camera stream have different guarantees on the same system. The build system feels heavy, and it is what makes hundreds of packages by hundreds of authors compose without a central authority. The design serves a fleet of robots maintained by many teams, which is not the situation of someone with one board on a kitchen table. That mismatch is real, and it is a mismatch rather than a defect. The fair criticism is about defaults and error messages: a system that stays silent when two programs cannot agree is a system that teaches beginners to distrust their own code. Silence is the design flaw, not the architecture.
Does the difficulty go away once you have learned it?
Partly, but not the way you think. The six stop being obstacles within a few focused weeks, and after that the environment failures become recognisable in seconds rather than evenings — that part genuinely resolves. What does not go away is the ongoing tax: distribution upgrades that break packages, delivery settings that must be reconsidered every time a new sensor arrives, and the fact that every new person you onboard pays the same entry cost you did. Experienced teams do not describe the ecosystem as easy; they describe it as familiar, which is a different claim. The other thing that persists is architectural. Once the number of nodes grows, the questions move from "why is nothing arriving" to "which callback is holding the thread when the arm hesitates", and those are harder questions with less written about them. Learning ROS 2 converts a wall into a slope. A slope is much better than a wall, and it is still uphill.
How do you decide whether to push through or step around?
Decide by asking what your project would lose if the ecosystem vanished tomorrow. If the answer is mapping, navigation, a driver you rely on, or the ability to hire someone who already understands your robot, push through the six and stop treating them as a verdict on your ability — they are a curriculum, and it is short. If the answer is nothing, then five of the six are solving problems you do not have, and continuing to pay for them is a habit rather than a decision. Ask a second question to break ties: is this robot one computer or several? Several machines on a network is where the mature design justifies itself completely. One machine running several languages is where a shared-memory transport removes work you would otherwise do by hand. Ask a third if still undecided: who else has to run this robot? A system only you can start is fine alone and expensive the moment a second person joins.
Decide by situation rather than by preference:
- If borrowed drivers, mapping or navigation are the project -> push through ROS 2, because the six are a one-time cost against work you cannot reproduce.
- If you are losing days to environment drift -> a prepared container image, because two of the six become someone else's problem.
- If your robot is one machine running Python, C++ and Rust parts -> a shared-memory middleware, because the language boundary is where your time is going.
- If a demo lands this month -> whatever already runs, because switching mid-schedule costs more than the friction you feel now.
- If your team already knows the ecosystem -> ROS 2, because shared vocabulary beats a smaller concept count every time.
When the call is close, weigh it on the five axes of the HORUS Fit Framework — ecosystem size, setup effort, team size fit, deployment target, and licence — and take the option that loses on the fewest. No score, no numbers: five honest questions about your situation rather than about the software. If you keep landing on one machine, more than one language, and behaviour only you understand, star HORUS on GitHub so it is in your list when you start building.