HORUS/blog

Sep 5, 2026 · middleware · migration · team-decisions · ros2

When Is It Too Late to Change Robotics Middleware?

The window closes at four specific milestones, not at a date. Here is how to tell which side of them you are on, and what to do from each side.

It is too late once customers depend on the current build; before that, moving between ROS 2 and HORUS costs a quarter, not a company. The cost grows with how much has been written against the old choice rather than with calendar time, so a large young codebase closes the window faster than a small old one. A genuinely new product line reopens it. The rest of this post is for a team that already committed, is now unhappy about it, and needs to know how much room is left.

Somebody said it in a retro, half as a joke, and then nobody laughed. Maybe we picked the wrong thing to build on. Everyone had privately thought it for a month, and hearing it out loud made it a real question rather than a mood.

Now the conversation happens every few weeks and goes nowhere, because both answers sound irresponsible. Changing means stopping, and nobody can say for how long. Staying means continuing to route around the same limitation, and everyone can already name the piece of software that exists only to compensate for it.

The estimates make it worse. Ask three engineers what a move would cost and you get a fortnight, a quarter, and a shrug, which is not disagreement about the work so much as disagreement about what counts as done. The one who says a fortnight is thinking about the message passing. The one who says a quarter is thinking about the launch files, the recording format, and the sensor whose driver only exists for what you have now.

And underneath all of it is the question nobody phrases directly, which is whether the team is still allowed to change its mind.

When is it too late to change robotics middleware?

It is too late once other people depend on the current build in ways you cannot renegotiate, and that happens at four identifiable moments rather than on a date. The first is customers: once units are in someone else's hands and a support promise exists, a foundation change competes directly with every obligation you already owe. The second is paperwork: once safety documentation, a certification file or a procurement contract names the stack, changing it means reopening a process that took months.

The third is people: once the codebase is larger than the team could rewrite in a season, migration stops being a project and becomes a phase. The fourth is data: once you have a recorded dataset the team trains and tests against, and that dataset lives in one stack's format, moving means either converting years of recordings or losing the ability to compare against them.

Hit none of those and you are early, whatever the calendar says. Hit two and the answer is almost always to draw a boundary rather than switch.

What is robotics middleware, and which part of it would you actually be changing?

Robotics middleware is the layer that lets the separate programs on your robot find each other and exchange data, and it arrives as a bundle of five or six things rather than one. There is the message transport itself. There is a way to describe messages so two programs agree on their meaning. There is a system for starting and supervising a set of programs together. There is a recording and replay format. And there are conventions about time and coordinate frames that every package silently assumes.

People picture the transport when they say middleware, and the transport is the smallest and most replaceable piece. The parts that make a change expensive are the other four, because they have grown into everything. Launch and configuration files quietly encode years of operational knowledge. The recording format became your dataset. The coordinate conventions became assumptions buried in geometry nobody has reread since it started working.

So the first useful question is not whether to change middleware. It is which of those five things is actually failing you. The plain-English guide to robotics middleware separates them properly.

What are your actual options when the current middleware stops fitting?

There are seven, and only two of them are the rewrite people are dreading. The cheapest is to stay and tune: reduce what the busiest stream carries, pin the deadline-critical program to its own core, and remove work from the loop that does not belong there. Next is to change what sits underneath ROS 2, which speaks to the wire through an abstraction layer, so a different transport can be swapped in without node code changing. Third is to merge two programs that already live and die together, removing a process boundary rather than replacing the foundation.

Then the structural ones. Run two stacks side by side with a bridge, which is how nearly every real migration happens. Move to a different foundation entirely, and this is where HORUS sits beside ROS 2 as a different answer to the same question: 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, published under Apache-2.0 and validated in simulation.

The last two are blunter: rewrite everything at once, or accept the ceiling as a business fact.

How do these options compare side by side?

Read the last column first. Most teams can strike four rows in a minute, and the argument worth having is between whichever two survive.

OptionWho it is forWhat it assumes you knowWhen to pick itWhen not to
Stay and tune what you haveTeams with a deadline inside a monthYour own code and where the time goesSomething must work in front of people soonThe same fix has already been applied twice
Swap the transport under ROS 2Teams whose complaint is network behaviourYour transport vendor's configuration filesDiscovery or Wi-Fi is the observed symptomNobody will own the tuning next year
Merge two programs into oneTeams with one hot pair of processesYour own process split and its historyTwo programs already start and stop togetherParts must crash and restart independently
Two stacks joined by a bridgeTeams shipping now and rebuilding slowlyBoth stacks, and the cost of a translation hopNew work can start clean beside old workNo single person will own the bridge
HORUSTeams whose same-machine data movement is the limitRust, Python or C++, and your process splitSeveral programs on one board pass heavy dataYou need mapping, planning or vendor drivers
Full rewrite onto a new foundationTeams early enough to absorb a stopThe old system honestly, and the new oneThe prototype has no customers yetField units already run the current build
A boundary for the next product lineTeams with a shipped product and a roadmapWhere your product lines genuinely separateThe current robot must keep working untouchedBoth lines will share one team and one build

What are the warning signs that the window is closing?

The window closes quietly, through a series of individually sensible decisions that each made leaving slightly harder. The clearest early sign is a dependency you did not write and could not replace: a depth camera whose driver exists for one stack only, a planner nobody on the team could rebuild, a visualiser the whole workflow assumes.

The second sign is a conversation pattern. An engineer proposes something, and the answer is not that the idea is wrong but that the stack does not do that. It happens twice, then monthly, and then the idea stops being proposed at all. A foundation you cannot leave gradually becomes a foundation that defines what the team is willing to imagine.

The third is a hire made for the vocabulary. The moment a candidate's fluency in one stack is a reason to prefer them, the choice has entered your hiring and started compounding.

The fourth is the compensating program with a nickname, maintained by whoever was least able to refuse. Why middleware decisions are so hard to reverse walks through how each of those forms.

Are you a solo builder, a startup, or a company with units in the field?

A solo builder can reverse this decision almost for free and should therefore worry about it least. One person holding the entire system in their head can rebuild the plumbing across a couple of long weekends, with no coordination cost and no institutional memory to migrate. Build what you enjoy building, and change your mind whenever the current thing annoys you enough.

A startup of roughly two to ten engineers is in the window where the question is genuinely hard. The codebase is already bigger than one head, the hardware is real, and a migration consumes a quarter that the runway may not have spare. This group should test the specific failure before deciding, because a transport problem and a badly drawn process boundary look identical from the outside and cost very differently to fix.

A company with units in the field is past the technical question entirely. The workable move is a boundary rather than a switch: leave the shipped robot alone, build the next subsystem the other way, and let the two coexist behind a bridge. Managing software across many deployed units explains why the shipped fleet dominates this call.

What hardware have you already committed to?

The hardware usually decides this before the architecture argument starts, and the deciding factor is the driver you did not write. A sensor with a vendor-supplied package for your current stack and nothing for the alternative has quietly closed the window on its own, because replacing that driver is a project in itself and the vendor has no commercial interest in helping. List every device on the robot and write down who supplies its software.

Compute layout matters next. A robot with everything on one board is a robot where every message is a same-machine message, which is exactly the case where a shared-memory foundation behaves differently from a network-shaped one. A robot split between an onboard computer and an operator station has a real network in the middle that no shared-memory arrangement removes.

Then there is the change that makes the question smaller. Moving the deadline-critical loop onto a microcontroller takes the messaging layer off the critical path entirely, and it is usually cheaper than a migration. Whether your robot should run one computer or several is the decision to settle first.

How much time do you have before the next thing has to ship?

With a month, the answer is no, and that is a decision rather than an evasion. Reduce what the busiest stream carries, close the tools nobody needs while the robot runs, give the deadline-critical program a core of its own, and cut scope. Each of those is reversible in an afternoon, none of them can break the demo the night before, and all of them teach you something about where the time actually goes.

With a quarter, you can prove the diagnosis and try the cheap structural fixes. Instrument first, then swap the transport underneath, then merge the two programs that already live and die together. Most teams find something surprising in the first fortnight, and the surprise is usually not the layer they were blaming.

With a year, decide by where the robot is heading rather than where it is. A product that will gain sensors, gain consumers of a single stream and tighten its timing is a product whose foundation is under rising load, and that is the case where changing early costs less than changing late. When to rewrite and when to live with it is the honest version of that call.

What does your team already know, and who would actually do the work?

Name the person who would do the migration before you discuss whether to do one, because that question ends most of these conversations honestly. Migrations are done by whoever understands both the old system and the new one, and on most teams that is one person who is already the busiest. If that person cannot be freed for a season, the decision has been made regardless of what the meeting concludes.

Existing knowledge is worth more than any property of the foundations being compared, and teams routinely value it at nothing. A group fluent in one stack recognises a strange failure in an afternoon because someone has seen its shape. The same group on unfamiliar ground spends a week, because recognition is precisely what is being rebuilt.

Language sets the floor. A team that writes only Python and has never had to reason about who owns a block of memory will find a shared-memory foundation asking a new kind of question. A team already in C++ or Rust finds the vocabulary familiar and the real cost becomes configuration. Which robotics stack survives contact with real hardware covers the same trade from the hardware side.

What do you give up by changing middleware late?

You give up a season of momentum, and that is the cost people underestimate most. During a migration every engineer is temporarily a beginner: the failures no longer look familiar, the tooling no longer sits in muscle memory, and work that took an afternoon takes three days. A whole team of temporary beginners is the real bill, and it appears on no comparison page.

You also give up the packages you did not write. Mapping, navigation, arm motion planning, calibration tools, the visualiser and every vendor driver either come with you or get rebuilt, and the rebuild is invisible in planning because those pieces only become visible when they are missing.

And you give up the tacit knowledge stored in settings nobody can explain. Every mature robot carries values arrived at through suffering, arrived at once, written down never. A migration reveals how many of them no living person understands, and rediscovering them is slow, unglamorous work that nobody puts in the estimate. What migrating actually costs and what you keep itemises this properly.

When is ROS 2 the better choice?

ROS 2 is the better choice for most teams asking this question, and HORUS is the wrong answer for a project whose real complaint is anything other than same-machine data movement. If what you need is mapping, autonomous navigation, arm motion planning, a way to see what the robot believes about the world, or a driver for hardware already on the bench, stay on ROS 2 and use the packages, because rebuilding them is a multi-year detour.

Stay on ROS 2 when the robot spans more than one machine, because a network-shaped foundation is the right shape for a network-shaped system. Stay when you are hiring, because candidates arrive fluent and are useful in their second week. Stay when the team is large enough that a shared standard beats any individual technical win.

And stay when you cannot yet name the requirement the current stack blocks. Changing on a hunch is how a team spends a quarter and arrives at the same symptom holding unfamiliar tools. The direct comparison of the two sets out where each one wins.

Is a full rewrite the only way to change robotics middleware?

No, and here is why: almost every migration that worked began as a boundary rather than a rewrite, and the ones that began as rewrites are the ones people write postmortems about. The working shape is to pick one subsystem that can fail without taking the product down, build it the new way, and run it beside the old system behind a bridge that translates messages across. The bridge costs you a hop and a piece of software somebody must own, and in exchange it converts a flag day into a drift you can stop at any point.

That arrangement also produces the evidence the argument needs. After a month you know what the new foundation is actually like on your hardware, with your team, rather than what its documentation implies.

The rewrite-everything version only makes sense in one situation: a prototype with no customers, no certification and no dataset worth preserving, where the team can absorb a full stop. How teams actually decide to switch describes what the successful version looks like from inside.

Does deciding it is too late mean you are stuck with this forever?

Partly, but not the way you think: what is closed is the option to replace the foundation under the current product, not the option to build differently. Product lines are the natural seam. The robot in the field keeps its stack, its paperwork and its support promise, while the next generation starts on whatever the evidence says it should, and the two share algorithms rather than plumbing.

The second escape is narrower and immediate. You can remove one process boundary that has become expensive, or move one deadline-critical loop onto its own chip, without touching the foundation at all. Both are weeks of work rather than seasons, and both address the symptom people usually blame the middleware for.

The third is to change what you build against. Keep your controller, planner and perception logic as ordinary code that takes inputs and returns outputs, with the messaging pushed to the edges. Algorithms port. Plumbing does not. Doing that now makes the next decision cheaper whether or not you ever make it.

How do you decide whether the window is still open?

Write down the requirement the current stack blocks, in one sentence, with something a customer would recognise in it. If the sentence names a product requirement and you have demonstrated the failure by experiment rather than argued it in a meeting, the change may be worth paying for. If the sentence says the team finds the stack unpleasant, that is real and it is not a reason, because no migration has ever fixed a morale problem.

Then check the four milestones honestly. Are there customers on the current build. Does any document name the stack. Could the team rebuild the codebase in a season. Does the dataset live in one stack's format. Each yes moves you from switching toward drawing a boundary.

Then price the three things people always omit: the drivers you did not write, the operational knowledge sitting in configuration nobody remembers writing, and the season during which everyone is slower. Signs your prototype will not survive production is worth reading before committing either way.

Here is the whole decision in five lines.

The HORUS Fit Framework compresses this into five axes you can score any option against: ecosystem size, setup effort, team size fit, deployment target, and licence. On a timing question, licence and ecosystem size do the heavy lifting, because those are the two you cannot quietly renegotiate once a product depends on them.

The cheapest moment to have an alternative in mind is long before you need one. Put HORUS on the shelf now: star it so it is in your list when you start building.

Found this useful? Share it:Discuss on HNShare on X