Sep 5, 2026 · robotics-framework · ros-2 · team-decisions · middleware-choice
The Hidden Cost of Choosing the Wrong Robotics Framework
The wrong framework rarely fails outright. It taxes every change, concentrates knowledge in one head and shows up as slow estimates. Here is the real bill.
Choosing wrong between ROS 2, a lighter middleware and your own plumbing costs you your team's attention, not a rewrite, and the workarounds are the bill. A bad fit rarely fails loudly; it taxes every change, so work that should take a fortnight drags and nobody can say why. The verdict flips when your robot's value is borrowed packages: then ROS 2 outweighs anything a lighter option such as HORUS would fix. The rest of this post is for a team lead who suspects the stack is the problem and needs to tell that apart from the ordinary difficulty of building robots.
Nobody on the team says the framework is wrong. What people say is that the new hire is still not useful in week five, that everything on the robot takes longer than the estimate, and that there is one engineer who understands why the machine will not come up after a cold boot while everyone else waits for them. You say it about specific things: the logging tool only works properly on one laptop; the arm behaves in simulation and drifts on hardware; the build takes long enough that people quietly stop running it; there is a script in the repository nobody wants to open. Reviews have a recurring sentence in them, which is that we cannot do it the normal way here. Estimates come back doubled and nobody can defend the doubling. And when someone finally suggests changing the layer underneath, the room goes quiet, because everybody can picture the three months of work and nobody can picture what is on the other side of it. That silence is the actual cost, and it never appears on a comparison page.
What does choosing the wrong robotics framework actually cost you?
The cost is engineering attention, and it is spread so thinly that it never appears as a line item anywhere. A framework that fits your robot badly does not stop the machine. It makes every change slightly harder than it should be, permanently. Someone wants to add a second camera and finds the message shapes have to be negotiated with two other parts of the system. Someone wants to run the perception code alone on their desk and cannot, because the machine only comes up when all of it comes up together. Someone writes a small helper to work around a startup ordering problem, and a year later three more helpers depend on that one, none of them are written down, and the author has left. The bill arrives as a hiring problem, an onboarding problem and an estimating problem at the same time, which is exactly why teams end up arguing about people and process instead. Middleware decisions are hard to reverse mostly because the cost never presents itself as a single decision you could revisit.
What is a robotics framework, in plain terms?
A robotics framework is the set of agreements your programs make about how they find each other, what data looks like while it moves between them, and how the whole machine starts and stops. That is the core of it. Around that core, most frameworks bring four other things with them: a build system that expects your code laid out a particular way, standard message shapes so that a distance reading means the same thing to everyone, tools for watching what the robot is doing while it does it, and an ecosystem of packages other people wrote. Those four are why the choice is heavy. You can replace the message-passing part of a framework in a week. You cannot replace the ecosystem, the hiring pool, or the habits your team has already formed around the build. When people say framework they usually mean the messaging plus all of that, which is why comparing frameworks purely on how messages travel misses most of what you are actually buying.
What are your actual options for the layer under your robot?
You have about seven realistic options, and most teams seriously consider only two of them. You can build on ROS 2, which brings mapping, navigation, drivers, simulation tooling and by far the largest community, along with workspaces, build tooling, message definitions and a learning curve every new hire pays. You can build on a hardware vendor's own SDK, which is complete for the machine you bought and stops at its edge. You can use a lighter middleware meant for programs sharing one computer: HORUS is an open-source real-time robotics middleware for Rust, Python and C++ where the three languages share the same shared-memory ring buffers, so messages between processes on one machine are not serialised, which suits a Python or C++ layer sitting above a Rust control loop. You can speak to DDS directly, or use Zenoh, and write the robot-shaped parts yourself. You can use a general message broker such as MQTT, familiar to anyone arriving from web work. You can write your own layer over sockets. Or you can keep one program and use threads, which stays a real answer for longer than most teams admit.
| Option | Who it is for | What it assumes you know | When to pick it | When not to |
|---|---|---|---|---|
| ROS 2 | Teams whose robot needs mapping, navigation or existing drivers | Linux, workspaces, message types, launch files | The value of the robot is packages other people wrote | The robot is one computer running only your own code |
| HORUS | Small teams mixing Python or C++ with a Rust control loop | Your message shapes and how your loops are timed | Programs on one machine share data while the robot moves | You need many borrowed packages or a large hiring pool |
| A hardware vendor's SDK | Teams building on one arm, rover or humanoid they bought | Only the vendor's documentation | The product stays inside what the vendor sells | You add hardware the vendor never sold you |
| DDS or Zenoh directly | Teams with networking experience and a specific requirement | Discovery, quality-of-service settings, network behaviour | You want the transport without the framework around it | Nobody on the team wants to own that layer |
| A general message broker | Teams arriving from web or fleet software | Brokers, topics, message formats | Parts are spread over a network and timing is loose | A control loop depends on messages arriving in time |
| Your own layer over sockets | Teams with an unusual constraint and time to spend | Sockets, data formats, timing, failure modes | Every option above is wrong for a reason you can state | You would rather ship the robot than the plumbing |
| One program with threads | Teams with one machine and one job to do | Threads and shared data in your language | Nothing on the robot must survive another part crashing | Two things must run without waiting for each other |
What should you choose if you are a five-person team with a product to ship?
Choose by the fraction of the robot you intend to write yourselves, because that single number decides more than any technical comparison. If most of the robot's behaviour will come from packages other people maintain, take the big ecosystem and accept its overheads; you are buying years of other people's work and the overheads are the price of admission. If most of the robot is your own algorithms on hardware you designed, the big ecosystem gives you a build system, a vocabulary and a large surface area to learn in exchange for packages you will not import. Five people is small enough that one engineer permanently absorbed by the plumbing is a fifth of your capacity, and that is the real comparison. Write down the five things your product does that a competitor cannot copy. If none of them appear in a public package, you are paying for an ecosystem as insurance rather than as capability, and insurance should be priced honestly rather than assumed.
What robot hardware makes a wrong framework choice hurt soonest?
Hardware that has to keep a rhythm punishes a bad fit fastest. A wheeled robot that drives around a warehouse tolerates a great deal of unevenness underneath it, because a late message means it corrects a moment later and nobody sees anything. A legged robot, a fast arm or anything balancing does not have that slack: the same lateness shows up as a visible stagger, a jolt at the end of a motion, or a gripper that closes before the arm has finished arriving. The second sensitive case is a robot with several computers on board, where the layer's network behaviour stops being an abstraction and starts deciding whether the machine works away from your desk. The third is a small board with a camera on it, where everything competes for the same modest resources and a heavy framework leaves less room for the actual work. Wheels forgive. Legs, arms and cameras on small boards do not, and they are the projects where the wrong layer becomes visible in weeks rather than years.
What if you have to ship in six months?
Do not change the layer underneath a robot you have to ship in six months. Whatever is painful today, a migration will not have paid for itself inside that window, and it introduces an entire category of failure your team has never debugged: programs starting in the wrong order, messages going nowhere because two sides disagree about a name, a machine that works on the bench and not in the field. Spend the six months on the product and write the pain down instead. Keep a plain list of every workaround you add, what it costs and what it protects against, because that list is the business case you will need afterwards and nobody can reconstruct it later from memory. There is one exception, and it is narrow: if the current layer is why the robot cannot do the thing you are selling, and no amount of working around it changes that, then you are not choosing between shipping and migrating. You are choosing between migrating and not shipping.
What if your team has only ever written Python?
A team that only writes Python should be far more careful about the layer than a mixed team, because the layer is where the language boundary will eventually appear. Python is comfortable for the parts of a robot that change every week, and enormous amounts of real robot work happens in it. What Python struggles with is holding a steady rhythm while also doing heavy work, and every growing robot eventually meets that wall. When it does, the usual answer is to move the timekeeping part into another language and leave the thinking in Python, which means your layer's job becomes carrying data between two languages on one machine. Frameworks differ sharply here. Some make the second language a first-class citizen, some make it a wrapper you maintain, and the difference will not be obvious in month one. If your team is Python-only today and expects to stay that way for two more years, weigh how a candidate layer handles that boundary before you weigh anything else. The plainer beginner's guide to choosing is worth reading alongside this if nobody on the team has chosen before.
How do you tell a framework problem from an ordinary robotics problem?
Ask whether the difficulty would exist if the robot were a single program on one computer, and if the answer is yes, the framework is not your problem. A sensor that lies near shiny surfaces, a motor that pulls to one side, a gripper that needs a firmer close on cold plastic and a model that behaves differently on real furniture are all ordinary robotics problems and no framework will help. Framework problems have a different shape. They are about parts rather than physics: something cannot be run in isolation, something cannot be restarted without restarting everything, two parts of the system disagree about the shape of a message, the machine only starts in one specific order, or adding a component means touching four unrelated files. Do this on paper with the last twenty tickets. Sort them into physics and plumbing. If plumbing is a small minority you have an ordinary hard robot, and swapping the layer would only add work. If plumbing dominates, the layer is genuinely costing you and the conversation is worth having.
What do teams try first when the framework fights them?
Teams first try to hide the framework behind their own wrapper, and it works for about a year. The wrapper starts as a kindness: three helper functions so nobody has to remember the awkward parts, a script so the machine starts in the right order, a small translation layer so your data shapes are pleasant. Then the wrapper acquires special cases for hardware differences, then a mode for simulation, then a fix for the thing that only breaks on the robot. Now you maintain two layers instead of one, you own the bugs where they meet, and new hires must learn the framework and your dialect of it. The second thing teams try is discipline, which is a code review rule that everyone must do things the normal way. That fails for a good reason: the rule asks people to pay a cost the framework should have absorbed. Neither attempt is stupid, and both buy real time. They stop working at the same point, which is when the wrapper needs a maintainer of its own.
What do you give up by moving off the most common choice?
You give up other people's work, and that is a genuine loss rather than a rhetorical one. The largest ecosystem means a sensor arrives with a driver already written, a mapping stack exists that would take you years, tutorials answer your new engineer's questions at midnight without your senior people being awake, and a candidate can arrive already speaking the vocabulary. Leaving that behind means every one of those becomes yours. You also give up a certain kind of legibility: an investor, an acquirer or a customer's engineering team recognises the common choice and asks no further questions, while an unusual one invites a conversation you have to be ready for. What you get back is a smaller surface area, less that has to be learned before anything moves, and a layer whose behaviour you can actually hold in your head. That trade is reasonable for a team whose robot is mostly its own code, and unreasonable for a team whose robot is mostly other people's.
When is ROS 2 the better choice?
ROS 2 is the better choice whenever the robot's value depends on work other people have already done. A machine that must build a map of a building and navigate it is a ROS 2 project, because mapping and navigation packages represent years of effort that no small team reproduces on the side. If the sensor or arm you bought ships only a ROS 2 driver, that settles it too. ROS 2 also wins when the robot spans several computers, when recording and replaying real runs is central to how you work, when you need to hire quickly from a pool that already has the vocabulary, and when a research collaboration expects to hand you packages. HORUS is not the answer for those projects, and choosing it there means rebuilding plumbing you could have inherited. The cost of ROS 2 should be stated plainly as well: significant learning before your robot does anything new, a build system your team must accept, and a strong preference for Linux.
Can you fix a framework mistake later without paying for it?
No, and here is why: the plumbing is the cheap part of the migration, and it is the only part anyone estimates. Rewiring how programs exchange data is mechanical work that a competent engineer does steadily. What actually costs you is everything wrapped around the plumbing. The startup ordering that took a month to get right. The calibration values living in a launch file. The tuning that makes the arm stop before it hits the table rather than just after. The tooling your team debugs with, which is often framework-specific and disappears overnight. The muscle memory of five engineers. And the fact that during the move, the robot must keep working for whoever is already depending on it, so you carry both layers at once. Teams that pay least are the ones who kept hardware access in one place and kept their decision-making code free of framework types, because then the move is relocating functions rather than untangling them. What a move off ROS 2 costs and what survives it is worth reading before you commit either way.
Is the framework really why your team is slow?
Partly, but not the way you think. The framework is rarely the direct cause of a slow team, and blaming it is a comfortable way to avoid harder conversations about scope, testing and whether anyone has run the robot this week. What a badly fitting framework does is amplify. A team without hardware tests is slow anyway; on a layer where nothing can be run in isolation, that team becomes unable to test at all. A team with knowledge concentrated in one person has a risk; on a layer whose startup behaviour is folklore, that risk becomes a bus factor of one. So the honest question is not whether the framework is why you are slow. It is which of your existing weaknesses the framework is multiplying, and whether a different layer would reduce the multiplier or simply move it. Fix the amplified weakness first if you can. If the weakness cannot be fixed while the layer stays, you have your answer, and it is now defensible rather than emotional.
How do you decide which layer your robot actually needs?
List the parts of your robot that must run without waiting for each other, then list the parts you intend to borrow rather than write, and the two lists decide it between them. If the borrowed list is long, take the big ecosystem and stop deliberating; the overheads are real and they are still cheaper than reproducing navigation. If the borrowed list is nearly empty and the independent-parts list is short, one program with threads will serve you longer than pride allows. If the borrowed list is empty but several parts must run at their own pace on one computer, a lighter middleware is the cheapest thing to live with, and the language boundary is what to examine closely. Do this before the architecture discussion, not during it.
- If your robot needs mapping, navigation or a vendor's driver -> ROS 2, because those packages are the product and rebuilding them is not.
- If your robot is one computer running your own code, with a Python layer above a loop that keeps time -> a shared-memory middleware, because that boundary is the expensive part.
- If you bought a complete arm or rover and stay inside it -> the vendor SDK, because leaving it early buys work rather than capability.
- If you ship in six months and the layer is merely irritating -> change nothing, because a migration will not repay itself inside the window.
- If the layer is why your product cannot do the thing you sell -> migrate now, because every month of delay adds workarounds you will also have to move.
When two options stay close, weigh them on the five axes of the HORUS Fit Framework: ecosystem size, setup effort, team size fit, deployment target, and licence. No scores and no numbers, just five honest questions about your situation rather than about the software, and the option that loses on the fewest is usually the one your team can live with. And if the shared-memory answer is the one your robot is drifting towards, star HORUS on GitHub so it is in your list when you start building.