Sep 5, 2026 · ros2 · middleware · build-vs-buy · startups
ROS 2 vs Writing Your Own: When Rolling Your Own Makes Sense
Build on ROS 2 unless your robot is narrow enough to use almost none of its ecosystem. Rolling your own pays off in one specific case, covered here.
Build on ROS 2 unless your robot is narrow enough that you would use almost none of its ecosystem, in which case write your own. Most teams that roll their own end up rebuilding logging, replay and process management badly, which is where the months go. The verdict flips when timing on one machine is the blocker, and an existing middleware such as HORUS already solves that piece. The rest of this post is for a small team that has already argued about this once and wants the argument settled with reasons.
The conversation always starts the same way. Someone senior says the framework is fighting us, and half the room nods, because everyone has lost a day to it recently. Your build takes long enough that nobody runs it casually any more. There is a document listing configuration settings nobody fully understands, written by a person who has since left. Two of your engineers have privately concluded that the parts of the system you actually use amount to a fraction of what you installed.
Then somebody says the sentence: we could write this ourselves in a month. And the honest thing is that they are not obviously wrong. Your robot is one machine, four processes, a handful of message types, and a loop that has to close on time. Stated like that, it does sound like a month.
What nobody in the room says out loud is that the month is not the risk. The risk is the eighteen months afterwards, when the person who wrote it is on a different team and a new hire asks why the robot stopped recording.
Should your team build on ROS 2 or write your own?
Build on ROS 2, unless you can list on one hand every capability you need and none of them is mapping, navigation, manipulation planning or a vendor driver. That test sounds glib and it is remarkably accurate. The value of ROS 2 is not the message transport, which is the part teams think they are rejecting. The value is everything around it: the packages, the tooling, the recorded runs, the fact that a new engineer arrives already knowing how it works.
Rolling your own makes sense when your robot is narrow and deep rather than broad. A machine that does one thing, on one computer, with sensors you wrote the drivers for anyway, gets very little from an ecosystem aimed at general-purpose robots. In that case you are paying a large tax for a service you do not consume.
The decision is therefore not about code quality or elegance. It is about how much of somebody else's work your particular robot would actually use, and whether your team can maintain the alternative for years rather than weeks.
What does robotics middleware actually give a team?
Middleware moves values between the programs that make up a robot, and provides the tooling that makes those programs debuggable. A robot is never one process. One reads the sensors, one estimates state, one plans, one drives the motors, and they are often written by different people in different languages.
So middleware supplies named streams anybody can publish to or subscribe from, a way to launch and shut down the whole set together, a way to look inside a running system without stopping the robot, and a way to record everything that happened and replay it at a desk afterwards. That last one is the capability teams undervalue most and miss most.
Underneath, middleware also decides whether a message is copied and converted into a neutral format on the way out and rebuilt on the way in, or simply handed over. That choice is invisible while the robot is undemanding, and becomes the entire conversation once it is not. What middleware actually does in a robot covers the mechanics in more depth.
What are the real options besides ROS 2 and a blank file?
There are about six, and the two extremes in the title are the least common outcomes in practice. You can take ROS 2 whole. You can write everything yourself. You can adopt a narrower middleware built for the timing problem rather than the ecosystem problem, of which HORUS is one — an open-source system 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. You can put your own code on top of a network-first transport and own the message contracts but not the plumbing. You can buy a commercial real-time framework, which is what programmes with certification requirements usually do. Or you can keep ROS 2 for the broad parts and own only the inner loop.
That last option is where most teams that start this argument actually end up, and it is worth putting on the table early rather than discovering it after six months of rewriting.
How do the options compare for a small team?
Here they are by who each one suits and what it assumes, rather than by which is technically strongest.
| Option | Who it is for | What it assumes you know | When to pick it | When not to |
|---|---|---|---|---|
| ROS 2 | Teams needing maps, navigation, drivers and a hiring pool | Linux, C++ or Python, packages and launch files | The hard part of your robot sits above the transport | Your machine uses almost none of the ecosystem |
| Write your own from scratch | Teams shipping one narrow machine they fully control | Concurrency, message contracts, and tooling you must build | The product is one loop in one box | Your robot must map, navigate or take vendor drivers |
| HORUS | Rust, Python and C++ teams whose loop misses its deadline | How your processes split across one machine | Several processes on one computer must agree in time | You need a mature navigation stack this quarter |
| Your code on a network-first transport | Teams whose data crosses machines or sites | Networking, and how to version your own messages | The link is the hard part, not the loop | You expected batteries included |
| A commercial real-time framework | Programmes with a certification requirement and budget | Your safety standard and your vendor's toolchain | Somebody external will read your paperwork | You are paying for it out of your own runway |
| Firmware only, no middleware | Single-purpose machines with one control loop | Embedded C, interrupts, your board's timers | Nothing in the loop needs a camera or a map | Two teams work on it, or runs must be replayed |
| ROS 2 plus your own inner loop | Teams keeping the ecosystem but owning the fast path | Both worlds, and exactly where the boundary sits | Only one subsystem has a timing problem | Nobody has capacity to maintain a bridge |
Notice how little of that table is about speed. Most of it is about people and what they will still be able to maintain in two years.
Should a three-person startup write its own middleware?
Almost never, and the reason is arithmetic rather than taste. With three engineers, one person writing infrastructure is a third of your capacity, permanently. Not for the month it takes to get messages flowing, but for as long as the company exists, because infrastructure needs upgrades, new hardware support, and a rewrite of the tooling every time the system grows a new part.
The exception is a team whose product genuinely is the low-level system: a robot whose entire differentiator is what happens between the sensor and the motor, with no perception stack, no map, and no third-party hardware. Those companies exist. If that describes you, the calculation changes, because the infrastructure is not overhead — it is the product.
Everyone else should assume that the engineer who wants to write the middleware is your most valuable person and should be working on the thing customers pay for. Build versus buy for robot software works through that trade-off with numbers you can put your own figures into.
What kind of hardware makes rolling your own defensible?
One computer, hardware you control, and no dependence on drivers other people wrote. That combination removes most of what an ecosystem provides, and it is the honest signal that a custom stack might pay off. If your robot is a single board driving motors you designed, reading sensors you integrated yourself, the packages you would inherit from ROS 2 are largely irrelevant to you.
The signal flips the moment a second computer appears. Once processes live on different machines, you inherit the entire set of problems that network transports exist to solve: discovery, dropped links, ordering, versioning between machines that upgraded at different times. Writing that yourself is a much larger undertaking than writing message passing within one box, and teams routinely commit to the second while quoting the cost of the first.
Off-the-shelf sensors push the same way. A lidar, a depth camera or an industrial arm usually arrives with a ROS 2 driver somebody already debugged, and rewriting that driver is unpaid work with no upside.
How does your delivery timeline change the answer?
A deadline inside a year says use ROS 2, almost regardless of your other reasoning. Custom infrastructure has a distinctive cost curve: it feels fast for six weeks, then flattens hard when you reach the parts nobody enjoys writing. Process supervision. Recording. Replay. A way to see what is happening on a robot that is currently in a customer's building.
The teams that get burned are not the ones who misjudge the transport. They are the ones who ship a demonstration on custom infrastructure, win a customer, and then discover their debugging story is print statements while the customer waits.
A longer horizon changes things genuinely. If you are two years from revenue and your architecture is still moving, owning the layer means you can shape it around the robot rather than the reverse. But be honest about which situation you are in, because every team believes it has more time than it has. Write down the date something must work in front of somebody who is not you, then decide.
What does your team need to know to own a transport layer?
Concurrency, memory ownership across process boundaries, and the discipline to version message formats you will regret. That is a genuinely different skill set from writing controllers or perception, and having one strong systems engineer is not the same as having a team that can maintain a system.
The specific test worth applying is this: can at least two people on your team debug a problem where a message arrives late rather than wrong? Late is harder than wrong. Wrong values show up in logs, and everybody knows how to hunt them. Late shows up as a robot that behaves slightly differently on Tuesday, and finding it requires a mental model of what your processes are doing to each other.
If exactly one person has that model, you do not have a capability, you have a dependency. That person will eventually go on holiday during an outage, and the rest of the team will discover how much of the system lived in one head rather than in the repository.
What does rolling your own look like when it goes wrong?
It goes wrong quietly, about a year in, and it looks like debugging getting slower every month. The transport is usually fine. What has happened is that the team never built recording and replay, so every investigation requires reproducing the fault on real hardware. A bug that used to take an afternoon at a desk now takes three days and a robot nobody else can use.
The second failure is versioning. Two processes disagree about a message layout after an upgrade, the robot behaves oddly rather than crashing, and it takes a week to find because nothing in the system checks that assumption.
The third is people. The author moves on, and the code is uncommented because it was obvious to the person writing it. New hires cannot search for answers, because there is no community to search. Every question routes through whoever has been there longest.
None of these appear in the month where the transport gets written, which is why the estimate always feels reasonable and always turns out wrong.
What do you give up by writing your own middleware?
You give up the ability to hire someone who already knows your stack, and you give up every debugging tool you have not personally written. Those are the two costs that compound. An engineer joining a ROS 2 team is productive in a fortnight because the concepts transfer. An engineer joining your in-house stack is productive when someone senior has explained it, which costs that senior person weeks.
You also give up the free option of borrowing. Six months from now your robot may need to do something your architecture did not anticipate, and on ROS 2 there is often a package that gets you to a demonstration by Friday. On a custom stack there is only your team.
What you gain in exchange is real and worth naming: nothing in the system is unexplained, upgrades happen when you choose, and there is no configuration surface nobody understands. For a narrow product with a stable team, that trade can genuinely be correct. For a product still finding its shape, it rarely is.
When is ROS 2 the better choice?
ROS 2 is the better choice for most robots most of the time, and specifically whenever your robot needs to know where it is, plan a path, or talk to hardware somebody else built. Mapping and navigation are years of work that already exist and work well enough. Manipulation planning is the same. Vendor drivers are the same. Rewriting any of those to avoid a framework you find irritating is a career-length detour taken for aesthetic reasons.
ROS 2 also wins whenever your team will grow, because it is what people already know, and whenever your robot spans more than one machine, because a network transport with real discovery is not a weekend project.
HORUS is not the answer when your problem is that you lack a navigation stack, a mapping package or a driver for the arm you bought. That kind of middleware addresses timing between processes on one machine, and no amount of good message handling supplies capabilities you have not written. Diagnose which of the two problems you have before shopping.
Is writing your own always slower to ship?
No, and here is why. For a narrow machine, a custom stack genuinely can reach a working demonstration sooner, because you skip everything the framework does that you do not need. No workspace layout to learn, no discovery behaviour to configure, no build system with opinions. Small teams building one focused product often do get to a moving robot faster this way, and the people who claim otherwise usually have not tried it recently.
The catch is where the curves cross. Custom stacks are faster to the first demonstration and slower to the tenth robot, because the missing tooling only starts costing you once several people are debugging several machines at once. If your product is one machine and stays one machine, the curves may never cross.
So the honest framing is not speed but shape. Ask when your project stops being one person on one robot, and whether that moment arrives before or after the date you have promised somebody something.
Does rolling your own give your team full control?
Partly, but not the way you think. You gain control over behaviour: nothing happens that you did not write, no configuration surprises you, no upgrade changes timing under your feet. That is real, and for teams that have been burned by an opaque setting it feels like relief.
What you do not gain is control over your calendar. Owning the layer means owning every future demand on it. New sensor with an unusual interface? Yours. Second computer added? Yours. Someone needs to replay a failing run from a customer site? Yours, and probably urgent. The work does not disappear, it just becomes unschedulable, arriving as interruptions during weeks you had planned for product work.
Teams describing themselves as being in control of their stack are often describing being on call for it. Ask your engineers how many of last quarter's unplanned days went to infrastructure they own. If that number is already uncomfortable with a framework doing most of the work, it will not improve when the framework is yours. Why projects outgrow their first framework traces how that pattern usually develops.
How should your team make this call?
Decide by writing down the capabilities your robot needs, then marking which ones ROS 2 would hand you for free. If that list is long, the argument is over and you keep the framework. If almost nothing is marked, you are paying for an ecosystem you do not consume, and a narrower answer becomes defensible.
Then apply the maintenance test, which is the one teams skip. Name the person who will own this layer in two years. If that person is your best engineer, or if it is nobody, you have your answer. And check whether the failing part is the whole framework or one subsystem, because replacing one loop is a quarter of work and replacing everything is a year.
If your hiring plan depends on people arriving with existing skills, note that ROS 2 is what candidates learn for jobs, which is a real cost of any custom stack.
Here is the decision in six lines.
- If your robot needs mapping, navigation or vendor drivers -> ROS 2, because rewriting those is years, not months.
- If your robot is one narrow machine you designed end to end -> your own stack, because you consume none of the ecosystem.
- If one control loop misses its deadline and the rest is fine -> replace that loop only, because a full rewrite is disproportionate.
- If you have a delivery date within a year -> ROS 2, because custom tooling costs arrive after the demonstration.
- If exactly one person understands your timing behaviour -> stay on the framework, because a dependency is not a capability.
- If your product genuinely is the low-level system -> write it, because that work is the thing customers pay for.
The HORUS Fit Framework reduces this to five axes: ecosystem size, setup effort, team size fit, deployment target, and licence. Score every candidate on all five and reject anything red on the axis you cannot afford to lose, which for most small teams is team size fit.
If the axis you keep failing is the timing one rather than the ecosystem one, HORUS belongs on your reading list rather than in this quarter's plan: star it so it is in your list when you start building.