HORUS/blog

Sep 5, 2026 · rtos · real-time · ros2 · control-loops

Do You Need a Real-Time Operating System for Your Robot?

Most robots do not need an RTOS. Tune Linux and fix the data path first; HORUS or ROS 2 usually meets the deadline before the kernel is the problem.

Most robots do not need a real-time operating system: a tuned Linux with ROS 2, or a shared-memory layer such as HORUS, meets the deadline first. An RTOS guarantees when your code gets to run, and does nothing about a message that must be copied and queued before arriving. The verdict flips when a missed deadline breaks something physical and the miss survives every fix above the kernel. This post is for someone already running ROS 2 whose loop misses deadlines under load and who is being told the kernel is the reason.

Your controller runs beautifully for minutes at a time, and then one cycle takes far longer than every cycle around it. The arm nods. Nobody can reproduce it on demand, but it happens more often when the log files are being written, more often again when someone opens the visualiser, and reliably during the demo. You added timing prints inside the loop and they say the maths is quick, so the time is going somewhere you cannot see. A colleague told you to install the real-time kernel patch, someone else said to pin the process to its own core, a third person said the whole design is wrong and the motor loop belongs on a microcontroller. All three suggestions sound plausible, all three cost you a week, and you have no way to tell which one addresses your actual problem. What you want is not a lecture on scheduling theory. You want to know whether the kernel is genuinely your problem, and if it is not, where to look instead before you rebuild your stack around an answer to a question you never had.

Do I need a real-time operating system for my robot?

You need one when a late cycle causes physical harm and you have already ruled out every cheaper cause. That combination is rarer than the internet suggests. Most robots that miss deadlines are missing them for reasons above the kernel: a lock held while a file is written, an unbounded queue that grows a backlog, a memory allocation inside the control loop, a garbage collector, or a message being packed and unpacked on its way between two processes on the same machine. A real-time kernel fixes none of those. What a real-time kernel does fix is the case where your code was ready to run and the operating system made it wait — because a driver was busy, because a higher-priority task held the processor, because the scheduler simply chose otherwise. If you have measured that specific pattern, the kernel is your answer. If you have not measured anything yet, treat the RTOS question as premature, because it is the most expensive answer on the list and it addresses the least common cause.

What does a real-time operating system actually guarantee?

A real-time operating system guarantees an upper bound on how long your code waits for the processor, not that your code runs quickly. That distinction is the whole subject. A general-purpose kernel is built to get the most total work done and will let one task wait while it serves another, usually briefly and occasionally not. A real-time kernel gives up some of that total throughput in exchange for a promise: when a task is ready and nothing more important is pending, it runs within a bounded time, even when the machine is loaded. The consequence for a robot is that the loop spacing stays even, so a controller tuned on the bench behaves the same way in the field. What an RTOS does not do: it does not make your maths faster, it does not stop you from writing a loop that takes too long, it does not manage how data moves between the parts of your robot, and it does not save you if your deadline was never achievable in the first place. It bounds waiting, and nothing else.

What are my actual options for making a robot hit its deadlines?

There are more options than the two everyone argues about, and they sit at different layers. Above the kernel, you can tune ordinary Linux — real-time scheduling policy, a core reserved for the control thread, no swap, no allocation in the loop — which fixes a surprising share of cases for the price of an afternoon. At the data layer, you can change how the parts of your robot exchange messages: ROS 2 with a local transport and tuned settings, or a shared-memory middleware such as HORUS, where Rust, Python and C++ processes on one machine read and write the same ring buffers so messages are never serialised on the way across, which removes the packing step from the path between perception and control. At the kernel layer, you can apply the real-time patch to Linux. And below all of it, you can move the fast loop onto a microcontroller running a small RTOS, leaving Linux to do the thinking.

OptionWho it is forWhat it assumes you knowWhen to pick itWhen not to
Stock Linux, untunedEveryone at the startNothing extraLoops are slow and forgivingDeadlines are already missed
Tuned stock LinuxTeams with occasional late cyclesScheduling policy, core pinningMisses are rare and traceableThe kernel itself makes you wait
Linux with the real-time patchTeams whose waits come from the kernelKernel builds, driver quirksWorst case matters more than averageYour drivers are unsupported there
Small RTOS on a microcontrollerMotor and safety loopsEmbedded C, no operating system comfortsThe loop must never be lateYou need cameras, maps, Python
Microcontroller plus Linux boardMost robots that shipTwo toolchains and the link betweenFast loop and thinking loop differThe project is a weekend demo
ROS 2 on LinuxTeams with an ecosystem-shaped problemFrameworks, build tools, launch filesYou need drivers and toolingThe local handoff is your bottleneck
HORUS on LinuxTeams whose parts share one machineRust, Python or C++, and processesThe handoff must land inside a cycleYou need a kernel-level guarantee

What does a missed deadline look like on a real robot?

It looks like a machine that behaves differently depending on what else the computer is doing. A gripper closes a fraction late and drops the part, but only when the logger is running. A drone holds position indoors and drifts when the mapping node starts. A wheeled base tracks a straight line until someone opens the visualiser, then wanders. An arm that was smooth for an hour makes one sharp movement nobody can explain. The unifying pattern is that the physical symptom correlates with computer load rather than with anything mechanical, which is why teams spend weeks on the wrong subsystem — the motor is fine, the belt tension is fine, the encoder is fine. Another tell: the robot behaves better when you make the loop slower. That is not a fix, it is a diagnosis. It means the loop is not finishing its work before the next one is due, and the honest question is whether the work itself is too big, or whether the work is small and something keeps standing in front of it.

Do I need an RTOS if I am one person with a hobby arm?

No. A single-person project with a hobby-grade arm should tune what it has and spend the saved weeks on the robot. Set the control thread to a real-time scheduling policy, keep it off the core doing camera work, stop allocating memory inside the loop, and move logging out of the control path. Those four changes are an afternoon each, they need no new kernel, and they resolve most hobby-scale lateness. Building or installing a patched kernel is not hard, but it puts you on a support path where a driver for your camera or your motor board may not be maintained, and debugging that is not a hobby-evening task. The other honest point for a solo builder: your arm's gearboxes and its plastic have more slop in them than your loop has jitter, so tightening the software timing will not show up in the motion. Spend the time on mechanics or on the control law instead, and revisit the kernel if you later build something stiff enough to notice.

Does the answer change on a microcontroller versus a Linux board?

Yes, completely, because a microcontroller with a small RTOS gives you timing that a shared Linux board cannot promise. On a microcontroller nothing else is competing: no page cache, no display server, no background updater, no other processes. That is why serious robots put motor commutation, current limits and the emergency stop on a microcontroller, and leave perception, planning and logging on Linux. The design question then is not which operating system, but where to draw the line between them and what crosses it. Draw the line so that anything which must never be late lives on the small machine, and anything that needs a camera, a filesystem or Python lives on the big one. What crosses between them should be small and rare — a target, not a video stream. If you find yourself sending high-rate data across that boundary, the split is in the wrong place. And on the Linux side, the parts still have to hand data to each other, which is the middleware question rather than the kernel one: what middleware actually does in a robot.

What should I do if the robot has to work for a demo next month?

Do not change the kernel a month before a demo. Kernel changes ripple into drivers, and drivers are exactly what breaks at the worst moment on hardware you cannot easily replace. For a month-out deadline, work in order of reversibility: give the control thread a real-time priority and its own core, take file writing and network sends out of the loop, cap every queue so a slow consumer cannot silently build a backlog, and lower the loop rate until the misses stop so you know how much margin you are short. Every one of those is undoable in minutes. If the misses survive all of that, the next cheapest step is usually the data path — how the parts of the robot hand messages to each other — because that change is contained to your own code and does not touch the machine underneath. Keep the kernel swap as the plan for after the demo, when a broken camera driver costs you a day rather than the presentation.

Do I need kernel experience to get predictable timing?

No, and the belief that you do is why teams delay obvious fixes for months. The changes that recover most timing are ordinary application work: setting a thread priority, choosing which core a thread runs on, preallocating your buffers, and moving anything that touches a disk or a network out of the control path. All of those are a handful of lines in the language you already use, and none require reading kernel source; even in Python, where people assume timing is hopeless, most of the ceremony sits in how a node is declared rather than in the loop itself. Where real kernel knowledge starts to matter is when you build a patched kernel and then have to judge whether a specific driver is going to behave under it, or when you are chasing a pause caused by something in the operating system rather than in your code — that work is genuinely specialised and slow. A reasonable rule: everything you can change inside your own process, do yourself. The moment the fix requires changing what is underneath your process, budget serious time or bring in somebody who has done it before.

What do I give up by moving to a real-time operating system?

You give up total throughput, driver breadth, and a large amount of your team's attention. A real-time kernel deliberately trades average work done for a bounded worst case, so a machine that also runs perception or logging will get less of that work done overall. You give up some hardware support, because vendor drivers are written and tested against ordinary kernels, and a camera or motor board that worked yesterday may misbehave or fail to build. You take on the kernel as something your team now maintains, which means updates become an event rather than a routine, and it means somebody has to own that. And you give up simplicity of explanation: a new engineer can no longer assume the machine works the way every other Linux machine does. If a small RTOS on a microcontroller is the route instead, the price is a second toolchain, a second build, a second place bugs can hide, and a communication link between the halves that becomes its own source of interesting failures.

When is ROS 2 the better choice?

ROS 2 is the better choice whenever your problem is breadth rather than timing, which covers most robots. If you need lidar and camera drivers, a navigation stack, a simulator, transform handling and a visualiser, ROS 2 supplies them and no alternative comes close on that front. If your robot spans several machines over a network, ROS 2's transport is designed for it. If your team is growing, ROS 2 is the vocabulary new hires arrive with, and that alone can outweigh a technical edge elsewhere. ROS 2 also runs perfectly well on a real-time kernel, so choosing ROS 2 does not close the RTOS door. HORUS is not the answer for a team whose real difficulty is finding a driver for an unusual sensor, or whose robot is spread across a network — a single-machine shared-memory layer does nothing for either. Reach for a specialised data layer only when you have a deadline you keep missing and have traced the miss to the handoff between local processes, which sensor-fusion pipelines like combining wheel odometry and an IMU make easy to observe.

Is ordinary Linux simply unusable for robot control?

No, and here is why: a very large number of shipping robots run control loops on ordinary Linux, and they work because their teams removed the things that cause waiting rather than replacing the scheduler. Untuned Linux is genuinely a poor host for a control loop — it will let your thread wait while it does something it considers more useful, and it will do that at the least convenient moment. Tuned Linux is a different machine: a reserved core, a real-time scheduling policy, no swap, no allocation in the loop, and no file writes in the control path removes most of the waiting that people blame the kernel for. The residue that tuning cannot reach is real, and for a machine that can injure someone it is the difference that matters. But the claim that stock Linux cannot control a robot is usually made about an untuned system by someone who has not tried the free fixes. Try them first; they take an afternoon and they tell you where you actually stand.

Will a real-time kernel fix my jittery control loop?

Partly, but not the way you think. A real-time kernel fixes the part of your jitter that comes from waiting for the processor, and for many robots that is not where the jitter comes from. The common sources sit in your own process and in the path between processes: a mutex held during a slow operation, a queue with no bound letting a backlog build, an allocation that occasionally goes to the operating system for more memory, a Python part that pauses to collect garbage, and the packing and unpacking of every message that crosses a process boundary. Swap the kernel and every one of those is still there, now hidden behind a change big enough that you will assume you already fixed the problem. The order that saves time: measure where the loop's time actually goes, remove the waiting you control, then move the data path to something that hands messages over without re-encoding them, and only then change what is underneath. Teams that reverse that order usually end up doing all of it anyway.

How do I decide whether my robot needs one?

Decide by what a late cycle actually costs, then by what you have already ruled out. Write down the physical consequence of one missed deadline: the arm overshoots and marks the workpiece, the drone dips, the gripper drops a part, someone gets hurt. If the consequence is cosmetic or recoverable, tune what you have and move on, because an RTOS is a large permanent cost for a small recoverable problem. If the consequence is damage or injury, the requirement is a bounded worst case, and the cheapest honest route is usually a microcontroller owning that specific loop rather than a rebuilt Linux. Between those extremes, work up the stack in cost order and stop when the misses stop: tune the thread, bound the queues, remove disk and network from the loop, then fix how data crosses between processes, then change the kernel. Keep notes on what each step changed. The step that finally works tells you which problem you actually had, and that is worth more than the fix itself.

Where that leaves you, in the order most teams meet these situations:

When you compare the candidates, the HORUS Fit Framework keeps the comparison honest across five axes with no numbers in them: ecosystem size, setup effort, team size fit, deployment target, and licence. An option that wins four of them and loses the one your robot depends on is still the wrong option.

If the missing time turns out to be in the handoff between processes rather than in the kernel, put HORUS on your shortlist now — star it so it is in your list when you start building, instead of hunting for the name on the day the deadline finally bites.

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