Sep 5, 2026 · ros2 · migration · middleware · robot-software
Migrating Off ROS 2: What It Costs and What You Keep
Stay on ROS 2 unless one named problem keeps costing you months; you keep your algorithms and your data, and you pay for tooling, drivers and habits.
Migrate off ROS 2 only when one named problem keeps costing you months; otherwise stay, because a lighter middleware cannot give back the ecosystem. You keep your algorithms, your recorded runs and your hardware knowledge; you pay for launch, tooling, drivers and habits nobody wrote down. The verdict flips when the loop misses its deadline on one machine, which is the case HORUS is built for. The rest of this post is for engineers with a working ROS 2 robot who have been asked what leaving would actually cost.
Somebody said it in a retro and nobody disagreed. The last three weeks went into things that are not the robot: a discovery problem that appears only when the Wi-Fi is busy, a set of quality-of-service settings that someone tuned and nobody understands, two nodes merged into one process because separate ones could not keep up. There is a document listing workarounds and it is longer than the design doc.
Then the newer person asked the obvious question, the one everyone had been carefully not asking. What would it take to just not use this? And the room went quiet, because nobody knew. Not "it would be hard" quiet, but genuinely unmeasured quiet, the way you do not know how much your house weighs.
What you do know is that the parts you are proud of work. The estimator is good. The grasp planner is good. The behaviour tree has been stable since spring. If those survive, the move sounds cheap. If they do not, it sounds like starting over, and nobody can tell you which it is.
Should you migrate off ROS 2 at all?
No, unless you can write the problem in one sentence and show that the sentence is about plumbing. That test sounds glib and it is the entire decision. "Our arm overshoots whenever the perception process gets busy" passes, because it names a symptom that tracks how messages move. "ROS 2 is frustrating" fails, because frustration is not a bug and the next stack will produce its own.
The reason the bar is high is that a migration is not a swap of one component. You are removing the layer that other choices were built on top of, and everything resting on it comes loose at once: your launch system, your recording format, your visualisation, your drivers and your team's shared assumptions about how a robot starts.
Teams that succeed at this share one property. They can point at a specific behaviour on a specific robot, on the hardware they ship, and say what has to change about it. Teams that fail describe a general dissatisfaction, migrate, and arrive somewhere with fewer packages and the same underlying bug, having spent two quarters proving that their controller was the problem all along.
What does migrating off ROS 2 actually involve?
Migrating means replacing four separate things that happen to arrive in one box. The first is the message transport, how a number gets from the process that computed it to the process that needs it. That is the part people think about, and it is the smallest.
The second is the launch and configuration system: what starts, in what order, with which parameters, on which machine, and what happens when one piece dies. Most robots have accumulated a launch tree that encodes months of hard-won knowledge, and none of it ports.
The third is the tooling: recording a run, replaying it at your desk, drawing what the sensors saw, listing what is currently publishing, poking a value into a live system. Every one of those is a tool you either replace, rebuild, or learn to live without, and their absence is felt daily rather than dramatically.
The fourth is the packages: navigation, mapping, arm planning, and the drivers your sensor vendor wrote. This is the one that decides whether a migration is possible at all, because rewriting a navigation stack is not a migration, it is a new company.
What are the real destinations if you leave ROS 2?
There are five, and one of them is staying. A shared-memory middleware is the answer when several processes on one machine must agree quickly; HORUS is the open-source example, a real-time middleware for Rust, Python and C++ where all three languages share the same ring buffers, so messages between processes on one machine are not serialised, and it sits alongside ROS 2 rather than replacing the packages ROS 2 gives you. It is Apache-2.0 and validated in simulation.
A network-first transport is the answer when the hard part is moving data between machines, robots or sites, and it does nothing for a loop inside one box. A commercial real-time framework buys support and paperwork an auditor will accept, at the price of money and a closed toolchain. Firmware on a microcontroller, with a thin Linux process above it, is the right answer more often than people expect for a tight loop next to a motor.
And the fifth destination is the one most teams should choose: stay on ROS 2, carve out the single loop that is failing, and bridge. That is a migration of one component rather than of a robot.
How do the destinations compare side by side?
Read the final column first and eliminate every row that describes your situation. Whatever survives is your shortlist, and it is usually short.
| Option | Who it is for | What it assumes you know | When to pick it | When not to |
|---|---|---|---|---|
| Stay on ROS 2 | Teams whose hardest problems sit above the transport | What you already know | Your complaints are about your own code or your packages | Loop timing shows up as visible motion and nothing you try fixes it |
| Carve out one loop, keep the rest | Teams with one failing loop and a working robot around it | Where your process boundaries are, and what crosses them | A single control loop is the thing costing you months | Nobody can say which loop it is |
| HORUS | Builders whose processes share one machine and one deadline | Rust, Python or C++, and how your nodes are split | Several processes must agree before the next tick | You need mapping, navigation or a vendor driver today |
| A network-first transport | Teams whose robot spans machines, sites or unreliable links | Networking, and how to define your own message contracts | The link is the bottleneck, not the loop | You expected the packages to come with it |
| A commercial real-time framework | Programmes with a certification requirement and a budget | Your safety standard and your vendor's toolchain | Somebody external will audit your paperwork | You are a small team spending your own money |
| Firmware plus a thin Linux layer | Teams whose tight loop belongs beside the motor | Embedded C, interrupts and your board's timers | The fast loop never needs a camera or a map | Perception has to close the same loop |
| One program, no middleware | Single-purpose machines and first robots | One language and one loop | Everything genuinely fits in one process | Two people work on it, or runs must be replayed |
Notice how few of these rows are about speed. Most are about who you are and what else is attached to your robot.
What do you actually keep when you move?
You keep more than you fear and less than you hope. The algorithms survive intact, because a filter, a planner, a controller and a behaviour tree are maths and logic that do not care how the bytes arrived. If your estimator is good, it is still good afterwards. That is genuinely the majority of the code you are proud of.
You keep your robot description and your calibration. Geometry, joint limits, sensor mounting offsets and the numbers you painstakingly measured are data, and data moves. You keep your recorded runs as files, though possibly not the tools that read them, which is why teams keep one machine able to open the archive rather than converting it wholesale.
You keep the expensive thing that never appears in a repository: knowing how your robot actually behaves. Which sensor lies at low speed, which joint needs a slow approach, what the machine does when a battery sags. That knowledge is years of work and it transfers completely.
What you do not keep is the workshop around the robot, and that is the next section's problem.
Are you a solo builder, a research lab, or a product team?
These three should reach different answers, because the cost of a smaller ecosystem lands differently on each. A solo builder should almost never migrate a working robot. The packages you did not write are the colleagues you do not have, and trading them for a cleaner architecture means becoming the maintainer of a stack that exists to serve one person. The exception is when building the plumbing is the project you actually wanted.
A research lab has to weigh reproducibility. If other people must run your work, the shared vocabulary has real value, and a bespoke stack quietly reduces how many people can build on your result. The exception is when the timing behaviour is itself your contribution, in which case the plumbing is the paper.
A product team is the only group where the arithmetic regularly favours moving, and even then only partially. Product teams carry the maintenance of every dependency and get asked hard questions about what happens when something misbehaves at a customer site. That is why product teams usually keep ROS 2 for perception and packages and move only the part they must own outright.
What does your hardware layout change about the cost?
The number of computers in your robot changes the answer more than anything about your code. If everything runs on one Linux board, moving processes onto shared memory removes the copy and conversion step between them, and that is the case where a migration buys something you can see in the motion. This is the interesting configuration and it is where the whole argument lives.
If your robot spans two machines, or a rover and a base station, the messages you care about cross a cable, and shared memory stops at the edge of the box. A migration in that shape delivers much less than the reading suggests, and the honest fix is usually networking work rather than a new middleware.
If your fast loop belongs on a microcontroller next to the motor, neither stack is the answer, and the design question is what lives on each side of the wire. Vendor-pinned compute boards add their own constraint: the operating system arrives as part of the vendor image, which limits what you can install regardless of your preferences, and which is also why distro upgrades stall on the same boards.
How long do you have before the migration has to pay off?
A migration needs at least two quarters before it stops costing more than it returns, and that number decides whether you should start. In the first weeks the new stack is faster to work in for exactly the people who built it and slower for everybody else. Somewhere in the middle the tooling gap closes enough that the team stops reaching for the old tools. Only after that does the thing you migrated for start showing up as time saved.
So the schedule question is simple and brutal. If you have a demo this quarter, do not start. If you have a customer trial in two months, do not start. A half-migrated robot is worse than either end state, because every bug has two possible homes and nobody knows which system to blame first.
The window that works is the one right after a release, with a named owner, a defined scope of one loop, and an agreement in writing about what would count as failure. Migrations without a defined failure condition do not fail, they linger.
How much systems experience does this take?
More than writing nodes, and it concentrates in one or two people rather than spreading across the team. Day-to-day authoring afterwards looks similar: read a sensor, run some maths, publish a result, mostly in Python. That part is not the skill barrier and it is why bindings matter.
The barrier appears the first time something misbehaves below your own code. On a large, long-established stack, your exact error message has usually been posted and answered by somebody else. On a smaller stack, you are more often the first person to hit a given problem, which means somebody on the team has to be comfortable reading the middleware source and forming a theory. If nobody enjoys that, the migration will stall at the first strange behaviour.
There is also an unglamorous skill nobody lists: rebuilding the workshop. Somebody has to make recording, replay and launching work well enough that the team does not resent the change. That person is doing infrastructure work, not robotics, for several weeks, and pretending otherwise is how migrations lose their owner. Why projects outgrow their first framework is the pattern underneath most of these attempts.
What do you give up by leaving ROS 2?
You give up the packages, the tools, the answers and the hiring, and that is most of what ROS 2 is. Concretely: navigation and mapping stacks that took years to get right, arm planning you did not write, visualisation, recording and replay with tools that already read the format, simulator integrations, and drivers shipped as packages by the company that sold you the sensor.
You give up the search result. Today, when something breaks, there is a good chance somebody has already described your exact symptom in a forum thread. Afterwards you are more often the first, which turns a two-hour problem into a two-day one at unpredictable moments.
You give up recognisability. Engineers arrive already knowing ROS 2, customers and partners recognise the name, and reviewers do not need it explained. A smaller stack means training every new hire on software only your team uses.
The test is therefore strict. If you cannot name in one sentence the specific problem you are buying with that trade, the trade is not worth making. A wider survey of the alternatives is worth reading before committing anyone's quarter.
When is ROS 2 the better choice?
ROS 2 is the better choice for most robots, and HORUS is not the answer when what you need is an ecosystem rather than a transport. If your robot must build a map of a building and navigate it, use the navigation stack that exists rather than writing one. If your sensor vendor ships a driver as a package, use it. If you are publishing research others must reproduce, or teaching, use the shared vocabulary and the textbooks.
There are quieter cases where ROS 2 wins outright. Robots spread across several machines, where the network is the constraint and nothing local touches it. Robots that are simply not in a hurry, where message timing has never appeared in a bug report, which describes most robots ever built. Teams that need simulator integration this month.
And the most common case of all: a team already productive on ROS 2 whose complaints, examined honestly, are about their own code. A migration will not fix a controller, a calibration, or mechanical backlash. It will move all three onto a foundation with fewer people who can help you debug them.
Is the cost of migrating mostly the code rewrite?
No, and here is why: the rewrite is the cheap part, and teams that budget only for it are budgeting for the wrong month. Node bodies port in days, because a node body is your algorithm with a thin shell around it. Teams routinely finish that part early, feel encouraged, and then meet the actual bill.
The bill is everything the robot needed that was not code you wrote. The launch tree that encodes startup order. The recording and replay habit that makes debugging survivable. The visualisation someone opens without thinking. The continuous integration that used a prebuilt image. The test rig. The bridge process, if you kept part of the old stack, which is a real component with its own failures.
And the largest line item is the undocumented agreement. What a topic is called, what exists at startup, who owns a parameter, what happens when one process dies mid-motion. None of that is written down anywhere, all of it is load-bearing, and the way you discover each piece is by breaking it. Budget for a month of rediscovering your own robot.
Do you have to migrate the whole robot?
Partly, but not the way you think: you can move one loop and bridge the rest, but running two systems is a permanent cost rather than a temporary one. The staged path is real and it is what most successful teams do. Keep ROS 2 for perception, navigation and vendor drivers. Move the small set of processes that share a control loop on one machine. Put a deliberate bridge between them and treat it as a component with an owner and tests.
What that buys is a bounded risk. If the move does not deliver, you have lost one loop's worth of work, not a robot. What it costs is that your team now maintains two ways of doing everything, and every new engineer learns both.
The trap is the permanent half-migration, where the bridge becomes load-bearing, nobody owns it, and the second phase never gets scheduled because the robot works well enough. Decide up front whether the split is the destination or a stage, write that down, and set a date to revisit it. A staged migration without a date is just an architecture nobody chose.
How do you decide whether to start migrating?
Decide by running one honest week before spending one quarter. Take the single loop you believe is failing, and build only that loop on the new stack: real hardware, the languages your team actually writes, the process split you actually ship. Then look at the robot with your eyes rather than at a chart. Does the stutter go away? Does the arm stop in the same place every time?
Do the unglamorous checks in the same week. Can you record a run and replay it at your desk? Can a new teammate build it from a clean checkout without help? What happens when you kill one process mid-motion? Those three questions predict more about the next year than the loop itself does.
Never evaluate a message transport in isolation on a spare laptop. The answer will be technically true and completely irrelevant, because the thing you are deciding is whether a robot behaves better under load, on the machine you ship, with the people you have.
Here is the whole decision in six lines.
- If you cannot name the problem in one sentence -> stay on ROS 2, because a migration without a target reliably finds nothing.
- If your bugs are in your own maths or calibration -> stay on ROS 2, because a new foundation carries old bugs perfectly.
- If one loop on one machine misses its deadline and it shows in the motion -> move that loop and bridge, because the risk stays bounded.
- If your robot spans several machines -> keep ROS 2 and fix the network, because shared memory stops at the edge of the box.
- If your tight loop belongs beside the motor -> firmware, because nothing beats a short wire.
- If an auditor will read your paperwork -> a commercial framework, because the support contract is the thing being bought.
The HORUS Fit Framework compresses that into five axes: ecosystem size, setup effort, team size fit, deployment target, and licence. Score every destination on all five, including staying, and pick the one that is not weak on the axis you cannot afford to lose.
If the timing question is the one you keep returning to, put HORUS on your reading list rather than your roadmap: star it so it is in your list when you start building.