HORUS/blog

Sep 5, 2026 · zero-copy · shared-memory · middleware · beginners

What "Zero-Copy" Means for Your Robot, Without the Jargon

Zero-copy means one program reads data where it already sits instead of duplicating it, and it only matters once large messages move inside one computer.

Zero-copy means one program hands another the data where it already sits, instead of copying it, which is what ordinary message passing does. On a robot that moves camera frames between programs on one computer, skipping those copies is why the picture arrives while it is still true, which is what HORUS and shared-memory transports in ROS 2 aim at. It stops mattering when your messages are small. This post is for a beginner who keeps seeing the phrase in comparison pages and wants to know whether to care before choosing a stack.

You are comparing robotics frameworks and every page uses the same word. Zero-copy. Nobody says what it means, and the explanations you find open with words like serialisation and address space, which are two more things to look up before you can look up the first thing. Meanwhile you have a real question, and it is not academic. Your robot has a camera on it. The picture goes into one program that looks for something, the answer goes into another program that decides where to drive, and somewhere in there the whole thing feels heavier than it should. The fans spin up. The video in your viewer lags behind the room. When you wave a hand in front of the lens, the robot reacts a beat after you expected it to. You do not know whether that is the camera, your code, the language you wrote it in, or this copying business everyone keeps mentioning. That is the question worth answering.

Does zero-copy actually matter for the robot you are building?

It matters if two programs on the same computer pass large data between them, and it does not matter much otherwise. The test is the size of the thing being sent. Numbers from a wheel encoder, a battery level, a command telling an arm where to go — those are tiny, and copying them costs you nothing you will ever notice. Camera frames, depth images, the cloud of points a laser scanner produces, a stretch of audio — those are large, and copying them means the machine spends its attention moving bytes around instead of deciding what the robot should do next. The second condition is that the programs live on the same computer. If a message has to cross a cable or a wireless link, it gets packed and copied no matter what anyone promises, because that is what sending means. So the honest test is two questions: is anything you send big, and does it stay inside one machine? Two yeses and this matters to you. Anything else, and you can stop reading comparison tables about it.

What does zero-copy actually mean in plain language?

It means handing over the thing instead of photocopying it. Picture two people in an office who both need the same document. The copying way is for the first to run it through a photocopier and hand over a duplicate, which takes time and leaves two documents that can drift apart. The zero-copy way is to put the document on a shared desk that both can see, and for the first person to say when it is ready. The second person reads the original where it lies. Inside a computer, that shared desk is a region of memory both programs can reach. The camera driver writes the picture into it once. The program hunting for obstacles reads it there. No duplicate is made, no packing and unpacking happens, and the picture the second program sees is the same picture rather than a re-creation of it. Everything else about zero-copy is bookkeeping: how the two programs agree that the document is ready, and how the first one knows when it is safe to write the next one over the top.

What does a robot look like when copying is the problem?

The robot reacts to the world it saw a moment ago rather than the one in front of it, and the delay grows as you add features. That is the shape of it. Everything works when you have one camera and one program. You add a second program that also wants the picture, and now the picture is being duplicated twice. You add a recorder so you can see what happened afterwards, and that is a third. Each addition is reasonable on its own, and the total is a machine whose fans are loud and whose viewer runs behind the room. The give-away is that each program still looks fine when you examine it alone — none of them is doing anything obviously wasteful — but together they cannot keep up. The second give-away is the shape of the failure. It is not a crash. It is a stutter, a missing frame here and there, sensor readings that quietly go astray, a robot that stops a little later than it used to, and then one day stops too late.

What are your actual options for moving data between robot programs?

There are roughly eight, and they sit on a scale from simplest to most careful about large data. At the simple end, keep everything in one program, so nothing is sent anywhere and the question never arises. Then files on disk, which is how logging works. Then a socket you write yourself, or a message broker such as MQTT, both of which pack the data up and send it as though it were going over a network, even when both programs sit on the same machine. Then ROS 2 with its default transport, which does much the same but hides the plumbing and hands you the ecosystem in exchange, and ROS 2 configured to use a shared-memory transport, which removes copies for large messages when the conditions line up. Then Zenoh, which covers the one-machine and across-the-network cases with a single model. And HORUS, an open-source real-time middleware where Rust, Python and C++ share the same shared-memory ring buffers, so a Python program and a C++ program on one machine read the same message rather than each receiving a packed copy of it.

How do the ways of moving data between programs compare?

Pick by what your messages look like and where the programs live, because those two facts decide more than any property of the software itself.

OptionWho it is forWhat it assumes you knowWhen to pick itWhen not to
Everything in one programFirst robots and single scriptsOne language, and ordinary functionsNothing has to be sent anywhereTwo languages, or one part may crash alone
Files on diskLogging, replay, offline analysisWhere files go and how large they getYou need a record more than a live feedAnything that reacts in the moment
A socket you write yourselfBuilders with one link and a clear headPorts, framing, what happens on a disconnectThe link is simple and stays simpleThe robot grows past a couple of programs
MQTTFleets, telemetry, phones and dashboardsBrokers, topics, what happens when one diesMessages are small and travel farCamera-sized data inside one machine
ROS 2 default transportAnyone who wants the ROS ecosystemROS concepts, and how to configure a networkDrivers and tools matter more than copiesEvery program is squeezed onto one small board
ROS 2 with a shared-memory transportROS users with large messages on one machineMessage types, settings, when the rules applyYou need the ecosystem and the large dataNobody on the team wants to tune transports
ZenohTeams spanning one machine and manyA newer model and a smaller communityThe same code must work near and farYou want the most trodden path available
HORUSOne-machine robots mixing Rust, Python and C++One of those languages, and life outside ROSCamera-sized data crosses language boundariesYour project lives on the ROS package catalogue

Most robots end up using two of these rows rather than one: something careful for the large data inside the machine, and something simple for the small messages that leave it. Choosing the network-shaped option for everything and then wondering why the machine is so busy is the common mistake.

What should you use if you are a beginner with one small robot?

Use whatever is simplest, which usually means one program, and do not spend an evening on this question. A first robot reads a couple of sensors and drives a couple of motors, and every message in it is a number or two. Copying a number is not a cost, it is a rounding error on a rounding error, and arranging shared memory to avoid it is effort spent on the wrong problem entirely. What will actually slow you down at this stage is the thing every beginner hits: working out why a sensor reading is not what you expected, why the robot drifts left, why the loop sometimes skips. None of those are copying. Learn the phrase, understand the idea, and file it under things that matter later — because they genuinely do matter later, just not now. If you are still deciding what to install in the first place, the frameworks that do not need Linux is the earlier question and a better use of tonight than this one.

What should you use if your robot has a camera on a small board?

Then this is your problem, and a shared-memory path is worth arranging early. A small board has a modest amount of memory and a narrow road between the chip and that memory, and every duplicated frame competes for the same road as the work you actually wanted done. On a desktop machine you can be careless and get away with it. On a board the size of a credit card, being careless shows up as a robot that sees the world late. Two practical moves follow. Keep the camera driver and the programs that consume frames on the same board, so they can share rather than pack, and be deliberate about how many programs really need the raw picture rather than a summary of it. Then, when something has to leave the board, send the decision rather than the image — the answer is small, and the picture never is. If the underlying idea is still hazy, what shared memory actually is is the piece to read next.

What should you use if you need a demo working this month?

Use what you already know, copy freely, and revisit this after the demo. A month is not the time to change how your programs talk to each other, because that change touches everything and its benefit shows up only under load you have not built yet. If the demo already stutters, look first at the things that are cheaper to fix: how many programs want the same picture, whether you are drawing the video on the same machine that is processing it, whether you are recording everything when you only need the last stretch. Turning off the viewer is a change you can make in a minute; changing your transport is a week. If you genuinely cannot make the deadline without shedding copies, the smallest version is to merge the two programs that pass the biggest messages into one, so the data never leaves the process. That is ugly, it is temporary, and it works on the day of the demo, which is the only property that matters this month.

What should you use if Python is the only language you know?

Stay in Python, and postpone this until Python is visibly the thing standing in your way. Python is fine for a great deal of robot software and the usual advice to abandon it is premature. What is true is that Python feels the cost of copying more sharply than compiled languages do, because packing and unpacking a large message is work Python does slowly, and it is work you get nothing for. The moment you notice is specific and recognisable: you add a second Python program that wants the same camera frames, and suddenly both are behind. At that point you have two honest choices. Merge them, so the frame is never sent at all, which is free and often enough. Or move to a stack where a Python program and a faster program can read the same message out of shared memory instead of each rebuilding a private copy, which is the point at which the language boundary stops being a tax. Do not make that move before you have felt the problem.

What do you give up by choosing a zero-copy stack?

You give up the freedom to be careless, and often you give up the ecosystem that let you be careless in the first place. A shared region of memory has rules. Both programs must be on the same machine, and must agree on the shape of the data, and must agree about who may write and when, because the second reader is looking at the real thing rather than a private duplicate that cannot be disturbed. That means a mistake in one program is now visible to another. Debugging changes character too: you can no longer watch a message go past on the wire, because there is no wire. Then there is the ecosystem cost. The stacks built hardest around this idea are younger and smaller than the ones built around network-shaped messaging, so there are fewer drivers, fewer tutorials and fewer people to ask. And you still need a second path for anything leaving the machine, because a message going to another computer will be packed and copied regardless.

When is ROS 2 the better choice?

ROS 2 is the better choice whenever the drivers, the navigation stack and the tooling are worth more to you than the copies you would avoid, and that is most teams most of the time. If your robot has to map a room, plan a path, or move an arm to a place without hitting anything on the way, ROS 2 hands you working answers and everything else hands you a project. If you are hiring, or being hired, ROS 2 is the shared vocabulary. If your programs are spread across several computers anyway, the copies are unavoidable and the argument is moot. And if large messages really are your problem, ROS 2 has a shared-memory route of its own, so "we move camera frames" is not by itself a reason to leave. HORUS is not the answer when the package catalogue is why you came, because a single-machine middleware brings no drivers or planners with it. Choose on what you need to exist already, not on how messages travel.

Is zero-copy just a marketing word?

No, and here is why. The underlying distinction is real and dull: either the second program reads the bytes where the first one put them, or the bytes are packed, moved and rebuilt somewhere else. On large messages it is the difference between a computer that is thinking and one that is fetching and carrying. Where marketing does creep in is in the scope of the claim. A stack can be honest about avoiding copies on one path and still copy at the driver, at the language boundary, when you write a log, or when the message leaves the machine — so a page that says zero-copy without saying between what and what is telling you very little. The other overreach is implying it always matters. For small messages the copy was never the cost, and no amount of avoiding it will change how your robot behaves. Read the claim as a description of one path, and ask whether that path is yours.

Will zero-copy make your robot smoother on its own?

Partly, but not the way you think. Removing copies removes one reason the machine is busy, and a machine that is less busy has more room to do things on time. But a robot that stutters usually has several causes stacked on top of each other, and copying is only one of them. A language that pauses to tidy up memory will pause whether or not you copied. A control loop sharing a processor with a browser and a video encoder will be late regardless. A driver that blocks while waiting for hardware blocks all the same. The useful way to think about it is that avoiding copies raises the ceiling rather than repairing the floor: it removes an upper limit you would otherwise hit as you add cameras and programs, and it does nothing about a loop that was already being interrupted. The vocabulary for the rest of that picture is worth having, and latency, jitter and determinism explained simply covers it without the jargon this page avoided.

How do you decide whether this matters for your project?

Answer two questions tonight and you are done. First: what is the largest thing you send between programs, and is it a picture or a number? If it is a number, close the tab, because nothing on this page will change your robot. If it is a picture, a depth image or a point cloud, keep going. Second: do the sender and the receiver live on the same computer? If they do, copies are a real cost and worth designing around. If they do not, the network already decides your timing and the copies are noise beside it. There is a third question for later, once both answers point the same way: how many programs actually need the raw data, as opposed to a smaller thing derived from it? Teams often discover the cheapest fix is not a faster path but fewer things travelling down it. Sending a decision instead of an image beats sending an image quickly.

A short version, by situation:

When you compare stacks rather than mechanisms, the HORUS Fit Framework lines them up on five things that are not numbers: ecosystem size, setup effort, team size fit, deployment target, and licence. For this question, deployment target does most of the work, because one computer and a fleet lead to opposite answers.

HORUS is open source under Apache-2.0 and the repository is linked below. Star it so it is in your list when you start building.

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