HORUS/blog

Sep 5, 2026 · real-time · robotics-basics · control-loop · middleware

What Does "Real-Time" Really Mean in Robotics?

Real-time means meeting a deadline every time, not being fast. Most robots need only the soft kind, and here is how to tell whether yours is the exception.

Real-time in robotics means hitting a deadline every time, not being fast, so the choice is between hard real-time, soft real-time and best-effort code. Most robots need only the soft kind, where a late map or a dropped frame is untidy rather than dangerous, and both ROS 2 and HORUS serve that comfortably. That flips the moment one loop is holding the machine up against gravity. The rest of this post is for a beginner who keeps meeting the phrase on spec pages and wants to know whether it applies to their robot.

You did not go looking for this phrase. It found you. It was on the product page of the controller board you were about to buy, in the second paragraph of a framework's front page, and in a forum reply telling you, with some confidence, that what you were attempting was impossible without it. Someone in a comment section said you needed a real-time operating system. Someone else said that was overkill and you should ignore the whole topic. Nobody defined the word.

Meanwhile the robot on your desk mostly works. The motor spins when you tell it to. The sensor reading arrives and the number looks about right. Then, every so often, something happens that you cannot reproduce: the wheels lurch when you open a terminal, the servo hums and settles a fraction off where you asked, the camera window freezes for a breath and everything catches up at once. You are not sure whether that is the thing the word describes, or a bug in your own code, or simply what robots are like. That is the question underneath the question.

Does your robot actually need real-time timing?

Probably not in the strict sense, and the robots that do need it are easy to spot once you know their shape. If your robot drives somewhere, looks at something, decides where to go next and acts at roughly the speed a person would notice, its timing sits far below the level where anyone would care. A map that updates late costs nothing. A route that arrives a moment behind schedule is replaced by the next one anyway. Now picture a different robot: a leg holding a body upright, an arm pressing a part into a fixture, a camera gimbal staying level on a moving vehicle. In those, the sensor reading and the motor command belong to the same instant, and a message that turns up out of turn shows up in the world as a twitch, an overshoot, or an arm that does not stop before it hits the table. The test is not whether your robot is quick. The test is whether anything on it is holding itself up, pressing against something, or balancing, because those are the jobs that punish lateness.

What is a real-time system in plain terms?

A real-time system promises an answer by a stated moment and counts an answer arriving after that moment as wrong. That is the part the phrase hides: real-time is not a synonym for quick. A bus that is usually early and occasionally an hour late is not a timetable, however flattering the average looks, and software behaves the same way. A program that normally answers straight away and now and then takes a long detour is not real-time, while a program that always answers within a bound you can name is, even if that bound is a generous one. The second half of the definition matters just as much. Timing is a property of a whole path, not of one part. The sensor driver, the operating system's scheduler, the layer carrying messages between processes and your own callback each get a chance to be late, and the robot only feels the total. One punctual component in a chain of careless ones buys nothing, which is why swapping a single library so rarely cures a stutter on its own.

What is the difference between hard and soft real-time?

Hard real-time means a missed deadline is a failure, and soft real-time means a missed deadline is a disappointment. In the hard case, being late is the same as being wrong: the leg buckles, the blade does not retract, the cutter carries on past the point where it should have stopped. In the soft case, being late costs quality: the video stutters, the map lags a step behind, the display shows a pose from a moment ago, and nobody is hurt. Engineers sometimes name a middle case, firm real-time, where a late answer is thrown away rather than used, which is exactly right for a sensor reading that a newer one has already overtaken. The useful insight for a beginner is that almost every real robot contains all of these at once. The wheels and the balance need one kind. The mapping, the logging and the screen you look at need another. The expensive mistake is deciding a whole robot belongs in one category and then paying the strictest price everywhere.

What are your options for making a robot's timing predictable?

There are five common answers, and only one of them involves writing anything unusual. The first is to leave the timing alone, which is the right call far more often than the internet suggests. The second is to tune the computer you have: a preemptible Linux kernel, thread priorities chosen on purpose rather than inherited, and memory allocated before the loop starts rather than during it. The third is to move the demanding loop onto a microcontroller, where nothing else competes for the processor and the timing becomes a property of the hardware. The fourth is to change the layer carrying messages between your processes: ROS 2 is the usual starting point and covers the whole robot, while HORUS is a smaller open-source project under Apache-2.0 aimed at the inner loop, where Rust, Python and C++ processes read and write the same shared-memory ring buffers so messages between them on one machine are never serialised. The fifth is to write your own, which is a genuine option and a far larger project than it looks. Whether ROS 2's own timing claim holds up is the natural thing to read next.

How do the main options compare side by side?

The honest comparison is not about which option keeps the best time. It is about what each one assumes you already have: a spare microcontroller, a spare month, or a colleague who has done this before.

OptionWho it is forWhat it assumes you knowWhen to pick itWhen not to
Leave the timing aloneFirst robots and hobby buildsOrdinary programming, nothing moreNothing on the robot fights gravityA loop is holding the machine up
A tuned Linux on the robotTeams staying where they areKernel options and thread prioritiesThe stutter follows unrelated activityNobody wants to own that setup forever
A loop on a microcontrollerSmall, self-contained control loopsEmbedded C and hardware timersThe loop can leave the main computerThe loop needs heavy sensor data
A real-time operating systemSafety functions and certified productsTask scheduling without Linux comfortsLateness must be argued about on paperYou still want ordinary Linux tooling
ROS 2 as it comesAlmost every robot with a route to planNodes, topics and launch filesYou want other people's partsEvery tick has to land on time
HORUSRust, Python and C++ on one machineOrdinary nodes, plus one new toolProcesses trade data on every tickYou need a large package ecosystem
A message layer you writeGenuinely unusual constraintsLock-free structures and memory lifetimesNothing off the shelf fitsYou have something to ship this quarter

Read the third column first. Most regret here comes from picking a row whose assumptions did not match the team, rather than from picking a row that kept poor time.

Which option fits you if you are building on your own?

If you are one person, or two people in a spare room, the deciding factor is how much of the robot you can afford to own yourself. Every row in that table is a promise about where your evenings go. Leaving the timing alone costs nothing and stays right until the day the robot has to balance. Tuning the computer means you own the kernel options and the priority scheme from then on, including the evening a new board arrives and none of the settings carry over. Moving a loop onto a microcontroller costs a board, a build setup and a second place for bugs to live, and buys timing that nothing on the big computer can disturb. Changing the message layer costs one new tool to learn and one boundary to maintain between the two halves of the robot. Writing your own starts a second project that competes with the first and rarely finishes. A solo builder should aim for the smallest number of things that can break at midnight, which usually means fixing one loop in one place rather than tightening everything.

Does your hardware settle this before you do?

Often, yes, and hardware settles it more firmly than any preference of yours. Start with where your code runs. If the parts of your robot that talk to each other sit on the same computer, the copying between processes is pure overhead, and removing it is available to you. If they are spread across a network, the link dominates everything and no local trick reaches across it. Then look at how much machine you have. A desktop-class processor hides a great deal of carelessness, because there is usually a spare core to absorb work nobody planned for, which is why code that behaved on your laptop starts stuttering the week it moves onto a small board bolted to the robot. Then ask whether a microcontroller is already in the design. If a motor driver board is already there, the cheapest fix is often to move the loop down to it and let the main computer think. And if your actuator only accepts commands at a fixed cadence, that cadence, not your software, is the deadline you have to meet.

How does your timeline change the answer?

The shorter your timeline, the less the timing matters and the more borrowed parts matter. If you have three weekends and want a robot that drives across a room, spend none of that time on scheduling: take the stack with the most drivers and examples, get the wheels turning, and let the loop be late occasionally. If you have a year and a product at the end, the reasoning inverts, because the loop you paper over now is the loop you rewrite under pressure the week before a customer visit. The middle case is the common one, and it has a cheap answer that costs nothing today. Build on the ecosystem, but keep the demanding loop behind one narrow interface: a function that takes the latest sensor reading and returns the next command. If that loop lives behind an interface, moving it later onto a microcontroller or a different message layer is a week of work. If it is smeared across nine nodes, a pile of callbacks and a launch file, moving it later is a rewrite with a deadline attached.

What skill does each option expect from you?

Each option asks for a different skill, and the gap between the skill it asks for and the skill you have is what sinks projects, not the option itself. Leaving the timing alone asks for nothing beyond ordinary programming. Tuning the computer asks for systems knowledge most beginners have not met yet: why allocating memory inside a loop is a landmine, what the scheduler does when two things are ready at once, why a thread given top priority can starve the process feeding it data. The microcontroller route asks for embedded work, a different craft with its own tooling, and is often more approachable for a beginner than kernel tuning because the machine is small enough to hold in your head. A real-time operating system asks you to give up conveniences you did not know you leaned on. A shared-memory message layer asks you to write ordinary nodes in a language you already use, then learn one smaller tool with fewer answers online at midnight. If you are still choosing that language, pick it by what you are trying to achieve rather than by reputation.

What do you give up by chasing tighter timing?

You give up other people's work, and the bill arrives long after the decision does. Predictable timing is bought with restriction. A loop that must never be late cannot allocate memory whenever it likes, cannot call a library that occasionally wanders off to do housekeeping, cannot log freely, and cannot share a thread with something slow. That rules out a surprising amount of convenient code, including much of what makes a first robot quick to build. Move down to a microcontroller and you give up the file system, the package manager and the ability to print your way out of a bug. Move off a large ecosystem and you give up drivers for the sensor you have not bought yet, a navigation stack that already handles the case you have not thought of, a visualiser showing what the robot believes, and recording and replay for the fault you cannot catch live. There is a quieter cost as well: two message layers in one robot create a boundary, and boundaries are where data goes missing at three in the morning.

When is ROS 2 the better choice?

ROS 2 is the better choice for most robots being built today, and pretending otherwise would waste your time. If your robot needs to work out where it is, plan a route and avoid a chair, ROS 2 hands you those parts along with years of other people's debugging. If your arm needs motion planning around obstacles, the same holds. If your system spans several computers or a fleet, ROS 2's discovery and tooling were built for exactly that, and a single-machine trick cannot help you. If you are writing this up for a course or a paper, a shared platform other people can rerun beats any timing win. If you are hoping to be hired, ROS 2 is what candidates have already touched. And if your real problem is that the robot does not yet know where it is, HORUS is not the answer, because no message layer solves localisation. The honest division is that ROS 2 owns the outer robot, meaning perception, planning, tooling and anything crossing a network, while a deadline-oriented layer earns its place only where one loop on one machine must land on every tick.

Is real-time just another word for fast?

No, and here is why the two keep getting confused. Fast is about the usual case and real-time is about the worst one, and a system can be excellent at the first while being hopeless at the second. A program that normally answers immediately and occasionally disappears for a long moment is fast and not real-time. A slower program that always answers within a bound you can state is real-time and not fast. Robots care about the second property because a control loop runs again whether or not the previous answer arrived. A reading that turns up after its slot is not late data, it is wrong data, and handing it to a controller makes the machine act on a world that has already moved on. This is also why buying a quicker processor so often fails to cure a stutter. A quicker processor improves the usual case and leaves the interruptions, the housekeeping and the scheduling decisions that caused the worst case exactly as they were. The robot still lurches, with more spare capacity while it does so.

Do you need a real-time operating system to get real-time behaviour?

Partly, but not the way you think. A real-time operating system is one tool for the job, and most robots reach acceptable timing without one. What such a system gives you is a scheduler that always runs the highest-priority ready task and stops doing anything else, plus a machine small enough that you can reason about everything competing for the processor. That is exactly what a safety function or a certified product needs. What it costs is the ordinary Linux world: the drivers, the file system, the package manager, and the ability to attach a debugger and poke around. Most teams get what they need from a preemptible Linux kernel, priorities chosen on purpose, and a loop that does nothing silly inside itself. And no operating system saves you from your own code, because a loop that allocates memory or waits on a slow device will be late anywhere. Treat the kernel as a floor you need before any measurement means anything. The longer version of this trade-off is worth reading before you buy hardware for it.

How do you decide what your robot needs?

Change one thing at a time and watch whether the misbehaviour follows it. Start the robot with only the demanding loop running, no logging, no camera, no visualiser, and see whether it behaves. Then add one part back at a time. The part that brings the fault back is your answer, and it is usually not the one you suspected. If the trouble appears when unrelated work starts, someone opening a terminal or a file being written to disk, the problem is scheduling, and a week spent on the kernel and your priorities is a week spent well. If it tracks how much data you send or how many processes are listening, the problem is the layer carrying messages, and moving the loop onto something built for a single machine is worth trying. If the fault is there with one loop running alone, the problem is your own code and no middleware will rescue it. And if the symptom is a pose that jumps rather than a loop that hesitates, start with the timing of the loop itself.

Where that leaves you, in five lines:

The HORUS Fit Framework is the short form of that list: judge any option on five axes, which are ecosystem size, setup effort, team size fit, deployment target and licence, then pick the one that loses least on the axis you cannot afford to lose. Beginners lose most often on setup effort, not on timing.

HORUS is open source under Apache-2.0 at github.com/softmata/horus. Star it so it is in your list when you start building.

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