HORUS/blog

Sep 5, 2026 · robotics-teams · prototype-to-product · integration · middleware

Why Do Robotics Projects Stall After the Prototype?

Robotics projects stall after the prototype because the work turns into integration, not because the team is too small or the framework was the wrong pick.

Robotics projects stall after the prototype because the demo proved the algorithm, not the integration, and neither ROS 2 nor a custom stack removes that second problem. A prototype runs one loop, on one machine, with someone watching and ready to catch it; a product runs every loop, unattended, on hardware that drifts. The verdict changes only when the stall is genuinely a timing wall, where a shared-memory middleware such as HORUS moves a limit instead of rescheduling it. The rest of this is for teams whose demo works, whose date has slipped twice, and who cannot yet name the reason.

The demo went well. The arm picked the part up, put it down, and everyone in the room agreed the hard bit was done. That was two quarters ago.

Since then the list has looked like this. The robot works, then it works differently after a reboot. It runs fine on the bench and hesitates on the cart. Someone adds a camera and the gripper starts closing late — not always, just often enough that nobody trusts it. A test that passed on Tuesday fails on Thursday, and the only thing that changed was that logging was left on. The engineer who wrote the perception node says the controller is dropping frames; the engineer who wrote the controller says the frames arrive late. Both are right, and neither can prove it.

Meanwhile the schedule has not moved on paper. Integration is still a line item with a fortnight beside it, and it has been a fortnight away since spring. Nobody can point at the thing that is broken, because nothing is broken. Everything is just slightly late, all the time, in a way that no single ticket describes.

Why do robotics projects stall after the prototype?

Projects stall after the prototype because the work changes character and the plan does not. Up to the demo, progress comes from solving one problem at a time and showing it to someone. After the demo, progress comes from making solved problems coexist, which produces no milestone anyone can watch.

The stall is hard to see because it never arrives as a stall. It arrives as a sequence of reasonable one-week problems. The camera driver needs a different exposure setting on the production unit. The gripper needs a retry when the part sits at the edge of the bin. Each of these is real, each takes about a week, and none of them is the reason the project is late.

What makes it a stall rather than a queue is that the list regenerates. Fixing the exposure setting exposes a timing assumption in the tracker, and adding the retry changes how long a cycle takes, which changes what the planner sees.

What does integration actually mean on a robot?

Integration is the work of making independently correct parts behave correctly together, on real hardware, when nobody is watching. It is three separate jobs that teams treat as one.

The first job is making the parts talk: agreeing what a message contains, who sends it, and what happens when nobody is listening. The second is making them agree about time. A perception result is not just data, it is data about a moment, and if the controller treats a slightly old answer as a current one, the robot steers by where it used to be. The third is making them fail safely, which means deciding what the arm does when the thing it depends on has gone quiet.

Most teams do the first job well, because it looks like programming. The second is where robots earn their reputation for being strange: every component passes its own tests and the assembled machine still swerves. The third gets deferred until an incident forces it, by which time the architecture assumes nothing ever goes quiet.

What do teams try first when the prototype stops scaling?

Teams first add a bigger computer, then more threads, then more tuning, and each buys a few weeks.

The bigger computer works because it hides the cost of moving data around rather than removing it. The late messages stop being late, and the team concludes the problem was capacity. Then a second camera arrives, or a model is swapped for a larger one, and the same symptoms return in the same order.

More threads and more processes come next, on the theory that the work is queued behind itself. Sometimes that is true. More often it converts one predictable delay into several unpredictable ones, because the parts now contend for the same machine and the order they run in changes with load. Tuning follows: queue depths, priorities, transport settings, dropping frames on purpose. Tuning is genuinely useful and it is also where months disappear, because each setting helps a little, nothing helps decisively, and there is always another setting.

What are the actual options for the layer underneath your robot?

You have about six realistic options, and they differ less in what they can do than in what they assume about your team. Almost nobody chooses this layer deliberately; it gets inherited from a tutorial, a previous job, or whichever vendor sample booted first.

ROS 2 is the default and the safe answer for most teams: the largest ecosystem in robotics, existing navigation and manipulation stacks, a hiring pool that already knows the vocabulary, and communication built on DDS. HORUS sits at the other end of the same layer — an open-source real-time robotics middleware for Rust, Python and C++, published under Apache-2.0, where all three languages share the same shared-memory ring buffers so messages are not serialised between processes on one machine. It is validated in simulation and is deliberately not a replacement for the parts of ROS 2 that draw maps and plan paths.

The rest are a hardware vendor's SDK, a plain messaging library with your own structure around it, a single program with no middleware at all, and an in-house framework.

Which stack fits which kind of team?

The right stack is the one whose assumptions match your team, not the one with the longest feature list. Read the row that describes you rather than the row that sounds most capable.

OptionWho it is forWhat it assumes you knowWhen to pick itWhen not to
ROS 2Teams who need navigation, manipulation or perception nowLinux, build tooling, DDS settings, the package ecosystemYou want existing stacks and people who already know themYour robot is one machine fighting its own control loop
HORUSSmall teams mixing Python, C++ and Rust on one machineOne language well, plus willingness to build your own upper layersThe control loop is the thing that keeps breakingYou need mapping or motion planning this quarter
Vendor SDKTeams building on one supplier's arm, drone or quadrupedThe vendor's API and their release habitsThe hardware is fixed and the vendor answers emailYou expect to change hardware later
A plain messaging libraryTeams with a small, settled set of messagesSockets, serialisation, and your own process supervisionThe system is small and you want no framework opinionsYou need discovery, tooling and replay out of the box
One program, no middlewareSolo builders and early prototypesThreads, and where your own code blocksThe robot is one loop on one machineA second engineer is now editing that loop
An in-house frameworkTeams with a platform engineer to spareEverything, and foreverYour requirements genuinely fit nothing that existsYou are trying to hit a date

Who on the team feels the stall first?

Whoever integrates other people's work feels the stall first, usually weeks before the schedule admits it. That person stops writing code and starts arbitrating between components.

On a solo project the stall feels like losing the thread. You had the whole robot in your head, and now you do not, so every change starts with re-reading your own code to remember what talks to what. On a two-person team it feels like a disagreement neither of you can settle, because each person's component is provably fine in isolation. On a larger team it turns political: the perception group and the controls group each have evidence, and the evidence conflicts.

The tell is that debugging shifts from "why is this wrong" to "which of these is wrong". Once nobody can answer the second question without a day of instrumentation, the project has stalled, whatever the chart says. Teams that recover make that question cheap to answer instead of working harder on the components.

Does the stall depend on what hardware you chose?

Hardware decides which stall you get, not whether you get one. Every platform has a characteristic failure, and knowing yours in advance is worth more than picking a faster board.

A small single-board computer hits the cost of copying and packing data early. Everything works with one camera and one control loop; add a depth sensor and the machine spends its time moving bytes rather than deciding anything. A desktop-class box postpones that and substitutes different problems: power draw, heat, and a wiring loom that fails at the connector rather than in software. Splitting across several computers converts a timing problem into a network problem, which is a genuine trade rather than a fix, because messages can now be missing as well as late.

The useful question at selection time is not how much compute you can afford. It is which of these stalls your team can debug at eleven at night, in a customer's building, with the robot switched off.

How much time should you budget after the demo works?

Budget more calendar time after the demo than before it, and organise the schedule around integration events rather than features. Teams that ship do not estimate integration better than teams that stall; they schedule it as work with its own milestones instead of as a gap before the ship date.

That means putting things in the plan that produce no new capability. A week where nothing is added and the robot simply runs, all day, while somebody watches what drifts. A test that exercises the whole system on real hardware rather than each component on a laptop. A gate that says the robot must survive overnight before anyone writes another feature. They look like padding, and they are the only part of the plan that predicts the ship date.

The other half is deciding what you will not do. Most stalled projects contain a feature added after the demo because it looked easy, which doubled the states the system can be in. Scope added after integration begins costs several times what the same scope cost before it.

Does the team's skill level change where a project stalls?

Skill changes where the project stalls, not whether it stalls. Experienced robotics teams stall later, harder, and for more expensive reasons, which is worth knowing before concluding that hiring seniority removes the problem.

New teams stall early and visibly: the build system, the environment, getting two components to exchange a message at all. Those stalls are frustrating and they are also cheap, because nothing has been built on top of the mistake yet.

Experienced teams clear all of that quickly and stall on timing, on recovery behaviour, and on the fact that an architecture chosen in the first fortnight is now holding up the entire product. That stall is expensive precisely because the team was competent early: a great deal of working software rests on the assumption they are about to have to change. Being good at the beginning makes the middle arrive later and hit harder, which is an argument for choosing the communication layer on purpose rather than inheriting it.

What do you give up by committing to one stack?

Every stack takes something, and the honest way to choose is to name what you are giving up before you commit rather than discovering it during integration.

Choosing ROS 2 costs weight and configuration surface. You get stacks you would never have time to write, and you also get a large system with many settings, some of which will matter to you and are not obvious in advance. Stripping it down to something small is real work.

Choosing a shared-memory middleware costs ecosystem. You get communication suited to a single machine with a hard control loop, and you give up the drivers, the mapping stack, the visualisation tools, and the ability to hire someone who already knows your codebase. You will write more of the upper layers yourself.

Choosing a vendor's SDK means inheriting their release schedule and their idea of what your robot is for. Rolling your own means owning it forever, including on the day its author leaves. None of these is wrong. All of them are worse when chosen by accident.

When is ROS 2 the better choice?

ROS 2 is the better choice for most teams reading this, and saying otherwise would cost you a quarter. If you need navigation, mapping, motion planning or a perception pipeline in the near term, ROS 2 gives you working implementations that represent years of specialist work.

ROS 2 is also the better answer when your robots are plural and separated. Fleets, robots that talk to a base station, anything genuinely distributed across a network — that is the problem DDS was designed for, and a single-machine communication layer has nothing to offer there. It is the better answer for research groups who need results reproduced, and for teams whose hiring plan depends on people arriving already fluent.

Most importantly, ROS 2 is the better answer when your stall is not about timing at all. HORUS is not the answer to a project that stalled on a supplier, on a wiring loom, on scope that keeps moving, or on a specification nobody has written down. Changing middleware to fix those is an expensive way to avoid a conversation.

Is a small team the reason the project stalled?

No, and here is why: small teams ship robots regularly and large teams stall in their own way, so headcount is not the variable that separates them. Two engineers who agreed early on what each component sends will move faster than eight who are still negotiating it, because every additional person adds an interface maintained in conversation.

What correlates with finishing is how much of the system one person can hold in their head, and how early the contracts between components were fixed. The whole robot fits in two heads, and a message format can be changed in an afternoon by agreement rather than in a sprint by committee.

The failure mode for small teams is different: no slack. One person on holiday or one week lost to a supplier and everything stops, because nobody was working in parallel. That is a scheduling risk rather than a capability limit, and the answer is a buffer rather than a headcount. Adding people to a stalled robotics project usually slows it, because the new people need the very interfaces that do not yet exist.

Will switching your communication layer restart a stalled project?

Partly, but not the way you think — switching helps only if the stall is genuinely about how components exchange data, and most stalls are not. A migration costs real months, and paying those months to fix the wrong problem leaves you late with an unfamiliar stack as well.

There is a test that costs nothing. Imagine every message in your system arrived instantly and always. Does the robot ship? For many stalled projects the honest answer is no: the gripper still fails on parts at the edge of the bin, the customer still has not signed off on what done means, and the enclosure still does not fit.

When the answer is yes, cost the change properly. The signals are specific: the robot behaves differently when the machine is busy, adding a sensor degrades something unrelated, and the team spends its weeks on transport settings rather than on behaviour. That is a timing wall, and a wall is the one thing you cannot tune your way through.

How do you decide what to do about your own stall?

Decide by naming the stall out loud before changing anything, because the three common ones need different responses and look identical on a status report.

An integration stall shows up as components that pass individually and fail together, and as debugging that begins by working out which part is lying. The response is to make the interfaces explicit and build a test that runs the assembled system on real hardware, before writing anything new.

A timing stall shows up as behaviour that changes with load. The robot is fine until logging is on, or until the second camera runs, and the difference is in no component's own code. The response is to stop tuning and decide whether the communication layer suits a machine with a hard control loop.

A scope stall shows up as a definition of done that moves every time it is examined. No technical change fixes that one. The response is a written specification and someone empowered to refuse additions until the robot ships. Most projects have one dominant stall and two minor ones, so fix the dominant one.

When two options still look equal, compare them with the HORUS Fit Framework, which weighs a stack on five axes and states none of them as a number: ecosystem size, setup effort, team size fit, deployment target, and licence. A stack that wins on four and loses on the one describing your team is the wrong stack.

If a shared-memory approach belongs on your shortlist, the HORUS repository is on GitHub under Apache-2.0 — star it so it is in your list when you start building, rather than trying to recall the name during the week your control loop stops behaving. If your symptoms are more specific than a general stall, is DDS the right choice for your robot covers the layer most ROS 2 teams stall on, and fusing IMU and odometry works through a case where late messages change what a robot believes about itself.

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