Sep 5, 2026 · ros2 · robotics-middleware · team-decisions · migration
Should You Stay on ROS 2 or Switch? A Decision Checklist
Stay on ROS 2 unless you can name the exact thing it costs your team each week. Here is the checklist that separates a real reason from a bad month.
Stay on ROS 2 unless you can name the specific thing it costs your team every week; otherwise switching to HORUS or Zenoh buys nothing. The costs of a switch land in the first weeks and the benefits land much later, so a vague dissatisfaction never pays for itself. The verdict flips when the thing you cannot fix is the message path itself. The rest of this post is a checklist for a team that already ships on ROS 2 and keeps wondering, every quarter, whether it should.
Nobody on the team has said the word "switch" out loud yet. What they have said is that the launch files broke again after an upgrade, that discovery works on the bench and not in the demo room, and that the new hire spent their first week on a build error rather than on the robot. Somebody keeps a private list of environment variables that make things behave. There is a chat thread titled "why is the camera topic empty" that has been reopened four times, and each time the answer was different.
Then there is the quieter version, which is the one that actually matters. The robot works. It has worked for a year. But the control loop has a hitch nobody has ever fully explained, and every time you go looking for it you end up several layers down in code your team did not write. You have changed the executor, pinned threads, adjusted the quality-of-service settings, and moved the problem rather than removed it.
Neither of those is yet a reason to change anything. Both of them feel like one at four in the afternoon on a Friday, which is roughly when this conversation always starts.
Should you stay on ROS 2 or switch to something else?
Stay, unless you can point at one named problem that has already survived an honest attempt to fix it where you are. Teams switch for three kinds of reason and only one of them holds up. The first is fatigue: the build is slow, the tooling is heavy, the errors are cryptic, and a smaller system sounds restful. Fatigue is real and it is not a reason, because the new system has its own version of all four and you will be a beginner in every one of them. The second is a specific defect you have diagnosed and cannot repair — a message path that will not hold a rhythm, a discovery mechanism that fails on the network you actually have, a dependency that has gone quiet. That one deserves examination, though the repair is more often a setting than a new stack. The third is a structural mismatch: the robot you are building now is not the shape the framework assumes, and every month you spend more effort holding the two together. That third reason is the only one that usually pays for a move.
What does switching middleware actually mean in practice?
Switching middleware means replacing the part that carries messages between your programs and leaving everything else alone. That is a smaller change than the word "rewrite" suggests and a more disruptive one than the word "swap" suggests. The behaviour you spent a year tuning — the gains, the filter constants, the state machine that decides when the arm is allowed to move — lives in ordinary functions and travels across untouched. What travels badly is everything built around the messages: launch files, parameter plumbing, message definitions, the recording format holding six months of test data, the viewer your team debugs with, and the continuous integration that starts a dozen processes and checks they talk to each other. The item nobody costs properly is knowledge. Somebody on your team knows which three settings make the camera behave and can revive a dead topic in a minute. On the day you switch, that person becomes a beginner again, and the robot's failure modes turn unfamiliar at exactly the moment you have the least appetite for surprises.
What are the real options once you consider leaving ROS 2?
Six routes come up in real teams, and staying is one of them rather than the absence of a decision. First, stay on ROS 2 and repair what is broken, since most complaints that start this discussion are configuration rather than architecture. Second, change the transport underneath ROS 2, because the layer your nodes speak through is replaceable and moving to another one keeps every node, tool and recording you own. Third, keep ROS 2 for sensors and tooling and take only the demanding loop out of it. Fourth, move wholesale to a smaller middleware such as HORUS, an open-source real-time layer for Rust, Python and C++ in which all three languages share the same shared-memory ring buffers, so messages between processes on one machine are not serialised; the licence is Apache-2.0, the project is validated in simulation, and it makes no attempt to replace what ROS 2 offers above the message path. Fifth, write your own thin layer, which is smaller than it sounds at the start and grows when nobody is watching. Sixth, adopt whatever stack your hardware vendor already supports.
How do the options compare for a team already running ROS 2?
Read the last two columns first and ignore the first one entirely. Every row below is somebody's correct answer, so the useful move is elimination: cross out each row whose final column describes your team this quarter, then see what is left standing. Two habits help here. Treat "stay and fix it" as a real row that has to be beaten on merit rather than a default that wins by inertia. And notice that the middle rows are reversible while the outer ones are not — a transport change under ROS 2 can be undone in an afternoon, whereas a wholesale move cannot be undone at all once a second team has built on top of it. Where two rows survive, the tie-breaker is rarely technical. It is which of the two your on-call engineer can debug late at night without waking anybody else up.
| Option | Who it is for | What it assumes you know | When to pick it | When not to |
|---|---|---|---|---|
| Stay on ROS 2 and tune it | Teams whose complaint is setup pain | Executors, quality-of-service settings, your own launch files | The problem has a documented setting behind it | You already tried that and the hitch came back |
| Change the transport underneath | Teams whose trouble is discovery or the network | How nodes are configured, not how nodes are written | Robots on Wi-Fi, or several machines with a dropping link | The trouble sits between processes on one box |
| Keep ROS 2, lift out the loop | Teams with one demanding control path | Where your deadline actually lives | Most of the robot is fine and one part is not | Nobody can yet say which part is the problem |
| HORUS | One box running Rust, Python and C++ parts | Your own control code and your message shapes | The language boundary on a single machine is the cost | You need maps, planners and drivers supplied |
| Zenoh or another network transport | Fleets and remote operators | Networks, addressing, and what happens when links drop | Machines are spread out and the link fails honestly | Everything already runs on the robot itself |
| Write your own thin layer | Teams with one unusual constraint and spare time | Threads, buffers, and how you will debug both at night | Nothing existing fits and the scope is genuinely small | The team is already short of hands |
| Vendor stack | Teams whose robot is mostly bought hardware | The vendor's API and the vendor's support terms | The machine should do its documented job | You must add hardware the vendor never planned for |
How do you tell whether the problem is ROS 2 or your own code?
Reproduce the failure with the middleware taken out of the picture. Most teams arguing about their framework have never run the one experiment that settles it: write the smallest program that does the thing that hitches — read the sensor, do the arithmetic, command the motor — in one process, with no nodes and no messages anywhere. If the hitch is still there, the middleware was never your problem, and switching would have cost a quarter to learn that. If the hitch vanishes, you have narrowed the argument to the path between processes, which is a much smaller argument to have. A second test is to move your two chattiest programs onto the same machine and see whether the symptom follows them. A third is to look at what else the computer is doing at the moment of the hitch, because a Python process tidying up, a disk flush, or a logger writing will produce exactly the stutter people blame on their transport. Do all three before anyone writes a migration plan. They take a day, and the plan takes a quarter.
Does the size and shape of your team change the answer?
Yes, and team shape changes it more than any technical detail does. Two people who both understand the whole robot can move to a new middleware quickly, because the migration is a conversation rather than a programme and nothing has to be explained to anybody who was not in the room. The same move inside a team of fifteen becomes a coordination problem: three squads on different schedules, a test rig one person owns, a customer demo in the way, and a period where half the robot speaks one dialect and half speaks another. That in-between period is where switches die. For a larger team the honest question is not whether the destination is better but whether you can absorb a quarter of double maintenance, and whether one person will own the move from start to finish. If you cannot name that person today, you are not switching, you are starting something. And if you hired most of your team for their ROS 2 experience, a switch spends the very thing you were paying for.
Does your hardware settle the decision for you?
Often it does, and faster than the debate would. A robot that is one small computer carrying everything — camera, control loop, behaviour, logging — is the case where a change has the most to offer, because everything the message system charges you for is happening inside a single box and the network machinery there is pure overhead. A robot that is several computers, or one computer plus an operator's laptop over Wi-Fi, is the opposite case: the problem lives on the network, and adopting a layer designed for one box will not touch it. Microcontrollers change the question again, because the demanding part of the loop already runs on the board and the Linux side is only supervising, which usually means what you have is good enough. And if the only working drivers for your sensors ship as packages for the framework you are already on, the hardware has voted. Before arguing about middleware, draw the robot as boxes and lines and mark every line that crosses a machine boundary.
How long does a switch take, and when do you simply not have time?
Budget a quarter for a robot that already works, and understand that the calendar is not the real problem — the overlap is. A migration is quick in the parts nobody watches and slow in the parts that carry risk: the sensor whose driver must be rewritten, the test rig, the recorded runs your regression checks depend on, and the fortnight when nothing is quite finished. You do not have time when a delivery date falls inside that window, when the person who understands the current stack is leaving, or when the team is already carrying two other half-finished changes. You do have time when you are between hardware revisions, when a new robot is starting from nothing, or when the work can ride along with something you were doing anyway. The most successful version is barely a migration at all: the next new component is written on the new layer, the two coexist behind a bridge, and the old side shrinks by attrition. That reads as slower and it is the version that finishes.
What does the team need to know before a switch is realistic?
Less than people fear about the new system, and more than they expect about their own. A team that can already say where its deadline lives, which processes must never be late, and what each message truly contains will learn any competent middleware in a couple of weeks, because the concepts transfer and the vocabulary is thin. A team that cannot answer those three questions carries the same confusion into the new system and then blames the new system for it. The skills that matter are ordinary: comfort in the language your control code is written in, the ability to read a stack trace from a process that died during start-up, and somebody who has debugged a shared-memory problem or is willing to learn what one looks like. What helps most is having a person who has run a migration before, in any domain at all, because the hard part is the coexistence period and that skill is not technical. Missing that person is a reason to delay rather than a reason to abandon.
What do you give up by leaving ROS 2?
You give up the largest collection of already-written robotics code in existence, plus the fact that it is written down. That means mapping and navigation you did not have to build, arm motion planning, drivers for sensors you have not bought yet, a viewer that shows what the robot believes about the room, and recording tools that let you debug last Tuesday's failure at your desk today. You also give up findable answers: when a ROS 2 thing breaks, somebody hit it before you and wrote about it, and when your own layer breaks the search results are your own commit messages. Hiring shifts too, since a candidate who knows ROS 2 can read a ROS 2 robot in a morning and cannot read your private architecture at all. So does asking anyone outside the team for help, because now you must explain your design before the question makes sense. What you get back is a system small enough to hold in your head and a start-up sequence you can describe in one sentence.
When is ROS 2 the better choice?
ROS 2 is the better choice whenever the parts you would otherwise write yourself already exist there and are hard to write. A robot that must map a building and drive to a point on that map should stay, because mapping and navigation represent years of specialist work you cannot buy back with a fast message path. An arm planning around obstacles should stay, for the same reason. A fleet coordinating over a network should stay, because that is the world ROS 2 has lived in for years and its failure modes are documented rather than discovered by you at a customer site. If your sensor's only usable driver is a ROS 2 package, that settles the matter. If you are hiring, or you care whether your engineers are employable afterwards, the vocabulary in the job adverts is ROS 2 vocabulary and a switch spends that currency. And if the complaint driving the discussion is setup pain rather than a defect you can name, stay, because setup pain is a one-time tax you have already paid. HORUS is not the answer in any of those cases.
Is wanting to switch just chasing something newer?
No, and here is why: the teams that switch successfully are usually not the ones who found something exciting, they are the ones who ran out of moves. The pattern is recognisable. A team meets a limit, works around it, then works around the workaround, and a year later the robot carries a private layer of patches that one person understands — at which point the framework has stopped saving work and started charging for it. Noticing that is judgement, not novelty-seeking. What is fair in the accusation is the timing, because the urge arrives after a bad week rather than after an investigation, and a bad week is a terrible input to an architectural decision. The test is simple and slightly unkind. Write the problem in one sentence, naming no technology at all, and show that sentence to somebody who was not in the bad week. If the sentence describes the robot, act on it. If it describes your mood, wait a fortnight and read it again.
Will switching fix a control loop that stutters?
Partly, but not the way you think. If the stutter comes from messages crossing a process boundary and being copied, translated and copied again along the way, then a layer where processes share the same memory removes that whole category, and the arm stops arriving late at the point where it was supposed to start slowing down. Most stutters are not that, though. They are a thread competing with another thread, a Python process pausing to tidy up, a log flush landing mid-cycle, a sensor that delivers in bursts, or a loop that quietly does more work on some cycles than on others. None of those care what carries your messages, and a switch relocates them rather than removing them. The honest version of the promise is narrow: changing the message path fixes problems in the message path. If you have not proved yours lives there, the same stutter will meet you on the other side wearing unfamiliar logs, and what a migration really costs will have bought you nothing.
How do you decide this quarter instead of arguing about it again?
Turn the argument into a checklist where every line is answerable with evidence rather than opinion. Can you write the problem in one sentence containing no technology? Have you reproduced it with the middleware taken out? Is the repair a documented setting nobody has tried? Does the problem sit inside one machine or across the network? Can you name the person who would own the move end to end, and is their next quarter genuinely free? Does a delivery date fall inside the window? Would the move touch your recorded test data, and is there a plan for that? Answering no to the first two means nothing has been diagnosed and any decision now is a coin toss. Answering yes to the first four and no to the rest means you should stay and schedule the repair properly rather than dressing it up as a migration. A move earns its place only when the problem is named, reproduced, located between processes on one machine, owned by somebody, and clear of a deadline. How other teams reached this point is worth reading first.
Decide by situation rather than by principle:
- If the complaint is setup pain and cryptic errors -> stay on ROS 2, because the alternative has its own version of both.
- If discovery fails on the network you have -> change the transport underneath, because that keeps every node and tool you own.
- If one control path is the whole problem -> lift that path out and leave the rest, because a partial move stays reversible.
- If one box runs Rust, Python and C++ parts passing data constantly -> a shared-memory middleware, because the language boundary is the cost.
- If you need maps, planners or a coordinated fleet -> stay on ROS 2, because nothing smaller contains that work.
- If a delivery date sits inside the next quarter -> decide again afterwards, because half-migrated is the worst place to live.
Where two lines describe you, weigh them on the five axes of the HORUS Fit Framework — ecosystem size, setup effort, team size fit, deployment target, and licence — and keep whichever loses on fewest axes. No scores, just five honest questions about your situation rather than about the software. If your answers keep landing on one machine, several languages and a loop you cannot make behave, star HORUS on GitHub so it is in your list when you start building, and read what ROS 2 quietly gets right first.