HORUS/blog

Sep 5, 2026 · message-broker · mqtt · robotics-middleware · ai-robotics

Does Your Robot Need a Message Broker?

No for the control path and yes for telemetry: a broker suits dashboards and remote commands, while the code that keeps a robot upright needs a middleware.

No for the control path — a robot needs a middleware there — though a message broker is the right answer for telemetry, remote commands and dashboards. A broker holds a message until someone collects it, which is exactly wrong when a late message is a wrong one, so control paths use ROS 2 or HORUS. The verdict flips if your robot is mostly a data reporter whose movements are slow and supervised. The rest of this post is for someone wiring a model or an agent into a robot and deciding what should carry messages between the pieces.

You already know how to make software talk to itself. You have shipped services that pass work through a queue, you have a broker you trust, and the robot in front of you looks like the same problem with wheels: a camera producing frames, a model consuming them, a controller taking the model's output, a dashboard watching all of it. So you stand up a broker, publish frames on one topic, subscribe from the model, publish commands back, and within an evening the robot moves. It genuinely works, and it works well enough that you tell someone.

Then it works less. The robot drives smoothly for a minute and then lurches, and the lurch lands whenever the model takes slightly longer than usual. You raise the buffer and the lurch becomes a drift, because the robot is now acting confidently on a picture of where it used to be. You lower the buffer and messages vanish at the exact moment you needed one. Someone suggests moving the broker onto the robot itself, which helps and does not fix it.

The suspicion creeping up on you is the awkward one: the piece of this system you were most confident about may be the piece that does not belong here.

Does your robot need a message broker?

Your robot needs a broker for the parts that talk to the outside world and does not need one for the parts that keep the robot upright. Those are two different jobs and it is normal for one machine to want both. Telemetry going to a dashboard, commands arriving from an operator, a fleet manager checking which robots are charging, a log shipped for later analysis — all of that is what brokers were designed for, and using anything else there is inventing work. The sensing-to-acting path is a different animal. There, a message that arrives after the moment it described is not merely late, it is false, and acting on it produces motion that looks wrong to anyone watching. Brokers are built on the principle that no message should be lost, which means holding it until someone takes it. Control paths need the opposite principle: if a reading is out of date, throw it away and use the next one. The question is not which technology wins. It is which half of your robot you are talking about.

What is a message broker, in plain terms?

A message broker is a separate program that sits between senders and receivers, accepting messages, holding them, and handing them on when a receiver is ready. That middleman is the whole point. Because the broker holds messages, a sender can carry on when the receiver is busy, a receiver can restart without losing what arrived while it was down, and something that comes online tomorrow can still collect what was published today. Those properties are exactly what a device reporting to a server wants, and they are why brokers dominate telemetry, notifications, and anything that crosses an unreliable network. The cost is that every message takes a detour: from your sender, into another program, out again to your receiver, with copies and encoding at each hop and a queue in the middle whose depth you must guess. On a network, that detour is invisible against everything else. Inside a robot, where two processes on one board are exchanging a picture many times a second, the detour is most of the story.

What are the actual options for moving data around a robot?

There are seven honest options and they split cleanly by which half of the robot they serve. For the outward-facing half you have an MQTT-style broker, a managed cloud service, or plain HTTP calls to your own backend. For the inward-facing half — camera to model to controller to motors — you have ROS 2, which handles both halves and brings an ecosystem of drivers and tools with it, or a smaller transport such as HORUS, 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. You also have two options people forget: sockets you write yourself between your own programs, and the simplest one of all, which is putting everything in a single process and calling functions. Most working robots use two of these at once and are better for it. The table describes situations rather than ranking software, because the right row depends on which half of your robot you are standing in.

Which option belongs in which part of the robot?

The option that belongs is the one matching what happens when a message is late. If lateness means a dashboard updates a moment behind, almost anything works. If lateness means an arm continues into a table, the choice narrows fast. Read the table with that test in mind, and notice that the fifth row — a broker outside, a middleware inside — is where most robots that have been running for a year end up, not because anyone planned it, but because each half found its own answer.

OptionWho it is forWhat it assumes you knowWhen to pick itWhen not to
MQTT-style brokerTeams reporting to a server or an operatorBrokers, topics, keeping a service aliveTelemetry, remote commands, fleet dashboardsA control loop depends on the message
Managed cloud serviceTeams with a fleet and no infrastructure peopleCloud accounts, credentials, connectivity limitsRobots in the field reporting homeThe robot must work with the network down
ROS 2Teams wanting drivers, mapping, navigation, toolsLinux, workspaces, launch files, package layoutBorrowed packages are most of the robotYou need one machine, one language, this week
HORUSMixed-language builders on a single machineYour message shapes and how loops are scheduledPython, C++ and Rust parts share data on one boxBorrowed packages are the value of the project
A broker outside, a middleware insideTeams with both a control loop and a dashboardWhere your boundary between halves actually sitsThe robot moves and also reportsNobody has time to own two systems
Sockets you write yourselfBuilders with one unusual link to makeConcurrency, framing, what happens on disconnectThe link is small and clearly definedThe list of special cases has started growing
One process, direct function callsSolo builders and early prototypesBasic Python or C++ and your hardware libraryNothing needs its own rhythm yetTwo parts must run at different speeds

What should you use if you are a machine-learning engineer rather than a roboticist?

Keep the broker for everything outside the robot and stop routing your model's inputs through it. The instinct that got you here is sound: decoupling producers from consumers is good engineering, and it is why your services survive deployment. The part that does not transfer is the assumption that a delayed message is still a useful message. In a service, a request that takes longer produces a slower response and a slightly annoyed user. In a robot, a frame that takes longer produces a command computed for a world that has moved on, and the machine acts on it with complete confidence. That difference is why robotics people obsess over staleness in a way service engineers rarely need to. Practically, the move is to put the camera, the model and the controller in one place with a direct path between them, and to publish outward only what someone outside actually needs: what the model concluded, not what the model saw. If you are building an agent on top, the same rule applies harder, which is worth reading about in what actually matters for agent-driven robots.

What if the model runs on a workstation and the robot is a small board?

Split the robot's behaviour so the board can act alone, and treat the link to the workstation as advice rather than control. Running a model off-board is a reasonable choice when the board cannot hold it, and plenty of good systems do it. What makes those systems work is that nothing safety-relevant waits on the network. The board runs its own loop, keeps the wheels turning or the arm on its path, and stops on its own if guidance stops arriving. The workstation contributes intent — go there, pick that up, avoid this area — and if the link degrades, the robot behaves predictably rather than freezing mid-motion. A broker is a fine choice for that link, because the link is a network and brokers are good at networks. What you must not do is close the fast loop across it. The test is simple: imagine the network pausing at the worst possible moment, and ask what the machine does. If the honest answer is that it keeps going into whatever is in front of it, the loop is in the wrong place.

What if you need something working in a month?

Use what you already know for the outside and put everything else in one process. A month is enough time to make a robot do one thing convincingly and not enough to learn two new systems while also debugging your own control logic. The single highest-value shortcut is refusing to split your robot into processes before you know where the seams are. Camera reading, model inference and command generation can live in one program with one loop, and on a modest board that arrangement often behaves better than an elegant multi-process design assembled from a diagram. Add your broker for the dashboard, because you want to see what is happening and you already know how. Then, when something forces a split — a model that must run at its own pace, a driver that only exists in another language — split along that specific line and only that line. Teams that arrive at a deadline with a sprawling architecture usually got there by dividing early, and dividing early is how a month of work becomes a month of integration.

What if you have never written control code before?

Expect the surprise to be timing rather than mathematics, and structure your first robot so timing mistakes are visible. Control code is not conceptually harder than the modelling work you already do, but it fails differently. A model that is wrong gives you a bad answer you can inspect at leisure. A control loop that is wrong gives you a machine that oscillates, and the cause is often not the formula but when the numbers arrived. So the first habit worth building is stamping every reading with the moment it was produced and checking that stamp before acting on the reading. The second is deciding, in writing, what your code does when a reading is missing or old — stop, hold position, coast, repeat the last command — because that decision will be made either by you or by accident. The third is keeping the loop that talks to hardware separate from the code that decides what to do, so you can test the decision without the machine. None of those depend on which transport you pick, and all three matter more than the pick.

What do people try first, and why does it stop working?

Almost everyone starts by publishing sensor data on a broker topic and subscribing from the code that needs it, and it works beautifully until the day something is busy. The first failure is the buffer, and it has two settings, both wrong. A deep buffer means nothing is lost, so when the model falls behind, the model works through a backlog of old frames and the robot reacts to a world that has already changed. A shallow buffer means the newest data wins, but now messages disappear during exactly the busy moments you cared about. The second failure is the extra hop: frames get encoded on the way out and decoded on the way in, twice, for data that never left the machine. The third is the ordering surprise, when a command overtakes the state it was computed from and a sanity check fires. Each is patchable, and the patches interact, which is how a clean system becomes a flaky one. The underlying mismatch is that you asked a delivery guarantee to do a timing job. That trade-off is examined more closely in where MQTT belongs in a robot.

What do you give up if you skip the broker entirely?

You give up the things brokers are genuinely excellent at, and for many robots that is a real loss. Without one you lose easy remote observation, so watching a robot from a laptop becomes something you build rather than configure. You lose store-and-forward, which is what lets a robot on a patchy connection report everything that happened once the link returns. You lose the ability for a tool written next year to subscribe to something published today without touching the robot's code. You lose a fleet story: brokers make a hundred robots look like a hundred clients, and rolling your own version of that is a project. And you lose the operational familiarity of a component your infrastructure people already understand, which matters more than engineers like to admit. This is why the answer for most real robots is both rather than either. Keep the broker for the outward-facing half where those advantages are decisive, and keep it out of the loop that decides how the motors move this instant.

When is ROS 2 the better choice?

ROS 2 is the better choice when your robot needs the software other people already wrote. If mapping, navigation or motion planning is what makes your robot valuable, those packages are the project and choosing anything without them means reproducing years of work. If your system spans several machines by design, ROS 2 was built for that and has been proven there for a long time. If you are hiring from a pool where everyone knows the tooling, shared vocabulary beats a better transport most weeks. If the depth camera you bought has one usable driver and that driver is a package, the argument is over. HORUS is not the answer for those projects, and picking it there trades an ecosystem for plumbing you would have to rebuild yourself. There is also a smaller case worth naming: if your robot genuinely does span a network of machines, some of the shared-memory advantage stops applying, because data crossing between computers has to be encoded no matter what carries it.

Is a broker fine as long as you run it on the same machine?

No, and here is why: moving the broker onto the robot removes the network but keeps the detour. Your data still leaves your process, enters another program, sits in a queue whose depth you guessed, and comes back out to your subscriber, with a copy and an encoding step at each boundary. For a status message that goes out occasionally, none of this matters and running the broker locally is a perfectly good decision. For a camera frame handed to a model many times a second, the copies and the queue are the problem, and geography was never the problem. The clue that you are in this situation is that local hosting helped and did not fix it, which is precisely what people report. The alternative is a path where two processes read and write the same region of memory without the data being copied or encoded between them, which is what shared memory means in practice and why roboticists keep bringing shared memory up in conversations that started about brokers.

Does running a broker and a middleware together mean doing everything twice?

Partly, but not the way you think. You do end up with two things to install, two sets of documentation and two failure modes, and pretending otherwise would be dishonest. What you do not end up with is two copies of your logic, provided you draw the boundary once and put it somewhere defensible. The pattern that holds up is a single small piece of code that acts as the border guard: it subscribes to what the inner system produces, summarises it, and publishes outward; and it takes commands from outside, checks them, and hands them to the inner system as intent rather than as direct motion. Everything inside knows nothing about the broker. Everything outside knows nothing about the middleware. That component is usually a couple of hundred lines and it is the most valuable code in the robot, because it is where you decide what an outsider is allowed to ask for. Teams that skip it end up with broker calls sprinkled through their control code, and that is the version where changing anything really does mean doing everything twice.

How do you decide?

Decide by asking what should happen when a message is late, and answer separately for each path in your robot. If the honest answer is that a late message is still worth having, a broker is correct and you should use the one you know. If the honest answer is that a late message should be thrown away because acting on it would be worse than acting on nothing, that path needs a middleware and no amount of broker configuration will change the underlying promise. Most robots contain both kinds of path, which is why most robots want both kinds of tool. Ask a second question to break ties: are the camera and the code that consumes the camera on the same machine? If yes, sending that data through anything that copies and encodes it is work you are paying for and getting nothing back. If no, the network is already your dominant cost and a broker is a reasonable way to manage it. Teams that grow past their first arrangement usually recognise the pattern described in outgrowing your middleware.

Decide by situation rather than by habit:

When the choice is close, weigh it on the five axes of the HORUS Fit Framework — ecosystem size, setup effort, team size fit, deployment target, and licence — and take the option that loses on the fewest. No score and no numbers: five plain questions about your project rather than about the software. If your answers keep landing on one machine, more than one language, and a model that must see the world as it is now, star HORUS on GitHub so it is in your list when you start building.

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