Sep 5, 2026 · real-time-robotics · latency · determinism · beginner-robotics
Latency, Jitter and Determinism: Three Words, Explained Simply
Latency is the delay, jitter is how much the delay varies, determinism is whether a run repeats. Jitter is the one that makes a working robot misbehave.
Latency is how long a message takes to arrive, jitter is how much that arrival time varies, and determinism is whether the robot repeats itself. Jitter decides whether your arm moves smoothly, because a loop tolerates a delay it always gets and cannot tolerate a surprise one; if your robot only logs and reports, none of the three changes your choice between ROS 2 and HORUS. The rest of this post is for someone building a first or second robot who keeps meeting these three words and cannot tell which one is their problem.
Your robot works, mostly. It drives across the room and stops at the wall, and then once every few minutes it lurches — same room, same code, same battery — and you cannot make it happen on purpose. You add a print statement to catch it in the act and the lurch moves somewhere else. You check the logs and every message you expected is there, so nothing was lost; something merely arrived later than the rest of the machine was willing to wait.
Then you go looking for help. Someone in a forum says the fix is real-time. Someone else says your middleware has too much latency. A third person says the word determinism as though saying it settles the matter, and you close the tab knowing less than you did before, because now you have three words and no way to tell which one is yours.
None of the tutorials you learned from mention any of this. A robot that drives forward and stops does not need to care what order things happened in. Yours has started reacting to the world, and once a machine reacts, when it knows something matters as much as what it knows.
Which of these three words is your robot's actual problem?
Jitter, in almost every case where a machine that mostly works misbehaves for no reason you can see. The three words describe different things, and only one of them is usually the cause of an intermittent fault. Latency is a delay, and a delay that happens every single time is something you can design around: if the wheels always respond a beat after the sensor sees the wall, you tell them to start turning a beat earlier and the robot behaves. Jitter is the delay that varies — usually short, occasionally longer — and there is no earlier you can move to, because the amount you would need to move by changes every cycle. Determinism is the biggest of the three: whether the whole machine, given the same start, does the same thing twice. Sort your own problem this way. If the robot is consistently a little late, that is latency, and it is tunable. If it is fine and then abruptly is not, that is jitter. If two identical runs end in different places, you have a determinism problem, and jitter is usually one of its causes.
What do latency, jitter and determinism mean in plain words?
Latency is the time between something happening in the world and your robot doing something about it, jitter is how much that time changes from one cycle to the next, and determinism is whether the same inputs produce the same behaviour every run. Picture a delivery. Latency is how long the parcel takes to arrive. Jitter is the gap between the fastest delivery and the slowest one. Determinism is whether the same parcels, sent in the same order, always leave the same thing on your doorstep. A control loop cares about all three, but not equally. A loop reads, decides and acts on a rhythm, and the whole arrangement assumes the next reading turns up before the next decision is due. A constant delay bends that assumption predictably. A varying delay breaks it at moments nobody chose. Determinism is what lets you say a fault will happen again if the robot is set up the same way, which is the difference between a bug you can fix and one you can only apologise for. It is worth reading what a control loop is and why its timing matters once these words start appearing in your own notes.
What are your options when the timing is not steady enough?
You have about seven realistic ways to steady a robot's timing, and the two cheapest ones cost nothing but attention. You can do less work inside the loop, which beginners skip and experienced people try first: move logging, image saving and anything that touches storage out of the path between sensor and motor. You can take the network out of that path, since Wi-Fi is the largest single source of surprise delay on a hobby robot. You can move the timing-critical part onto a microcontroller, which does one job forever and is never interrupted by an operating system. You can keep ROS 2 and tune what sits underneath it, with a real-time kernel and a core reserved for the loop, which is what teams heading for a product do. You can pick a middleware built for programs sharing one computer: HORUS is an open-source real-time robotics middleware for Rust, Python and C++ where the three languages share the same shared-memory ring buffers, so messages between processes on one machine are not serialised, and one common source of variation is simply not there. Or you can accept the wobble, which is right more often than the internet admits.
How do those options compare against each other?
The useful comparison is not which option gives the steadiest timing but which one matches the machine you have and the effort you can spend. Most of these are not exclusive, and the top two belong in every project.
| Option | Who it is for | What it assumes you know | When to pick it | When not to |
|---|---|---|---|---|
| Do less work in the loop | Anyone whose robot hesitates | Which step in your loop is slow | Logging, saving or waiting happens inline | The loop is already lean and still wobbles |
| Take the network out of the loop | Builders whose robot talks over Wi-Fi | Which messages cross the network | Faults track your signal strength | The parts genuinely live on different machines |
| A microcontroller for the fast part | Builders with a motor or balance loop | Simple embedded programming | The rhythm must never be interrupted | Your control code needs a large library |
| ROS 2 as it comes | Beginners leaning on borrowed packages | Linux, workspaces, message types | Mapping and drivers matter more than rhythm | A loop must keep time on a busy machine |
| ROS 2 with a tuned kernel | Teams heading for a product | System administration and scheduling | You need the ecosystem and the timing | Nobody on the team wants to own the kernel |
| HORUS | Small teams mixing Python with a Rust or C++ loop | Your message shapes and how your loops are timed | Programs on one computer trade data while the robot moves | You need borrowed packages or several computers |
| Accept the wobble | Learners and slow machines | What your robot is actually for | Nothing visible goes wrong when it happens | Something can be damaged when timing slips |
Should a beginner learning alone worry about any of this?
Not yet, and knowing the three words is still worth an afternoon. A first robot moves slowly, carries nothing valuable and stops when you take your hand off the controller, so a delay that varies costs you a slightly wide turn rather than a broken gripper. Chasing steady timing at that stage means installing kernels and reading scheduling documentation instead of finding out that your distance sensor lies near shiny surfaces. What the three words buy a beginner is diagnosis. When your robot lurches, you now know to ask whether the lurch is consistent, and that question alone will save you a weekend of rewriting logic that was never wrong. Keep the loop small, keep the slow work out of it, and let the machine tell you when it needs more. If you are still choosing what to build on, whether to start from a kit or a parts list will shape your timing problems more than any framework does, because a kit that arrives working removes the hardware causes you cannot yet tell apart from software ones.
Does this change on a Raspberry Pi or a similar small board?
Yes, timing trouble arrives sooner on a small board, and usually for reasons that have nothing to do with your code. A small computer runs everything on a handful of cores it shares with the operating system, the network stack and whatever else you left running, so your loop is competing for attention in a way it would not on a desktop. Writing to an SD card can stall for long enough that a motor visibly hesitates. A board that gets hot slows itself down to survive, so a robot that behaves in the first minutes starts wobbling later in a long run. Wi-Fi retries after a dropped packet and delivers a burst of stale readings. None of these are mysteries once you know to look for them, and all of them show up as jitter rather than as an error. The practical response on a small board is boring and effective: log to memory rather than storage, keep the control path off the network, and leave a core free for the loop that must keep time.
What should you do about timing two weeks before a demo?
Change nothing structural, and spend the fortnight on the two fixes that cannot break anything else. Swapping middleware, installing a real-time kernel or splitting your program into pieces two weeks before a demo introduces a class of failure you have never debugged, and it introduces it at the worst possible moment: programs that start in the wrong order, a machine that works on your laptop and not on the robot, a setting you changed and forgot. Instead, take work out of the loop. Move the logging, drop the frame rate you are feeding the vision code, stop writing files while the robot is moving, and put the machine on a wire if anything important crosses Wi-Fi. Then slow the robot down. A machine that moves more gently has more time to react, and most demo lurches disappear the moment the robot stops asking its own loop for the impossible. Write down every patch you applied, so that nobody mistakes a fortnight of triage for a design. The right week to restructure is the one after the demo, when nothing is at stake.
Do you need to understand real-time theory to fix a timing problem?
No, and the theory will make more sense afterwards anyway. Almost every timing fault a hobby or early-stage robot suffers is caused by one of five ordinary things: work in the loop that does not belong there, storage being written while the robot moves, a network in the control path, a computer that is busy with something else, or a language runtime pausing to tidy up memory. You can find and fix all five with no vocabulary beyond what you have just read. The theory becomes worth learning at the point where you have removed all five and the machine still misses its rhythm, because that is where you start needing guarantees rather than improvements, and guarantees is precisely what the theory is about. That is also the point where whether your robot needs a real-time operating system stops being a hypothetical question. Until then, treat real-time as a description of a property your machine either has or does not, rather than as a feature to go shopping for.
What does bad jitter actually look like on a robot?
Bad jitter looks like a machine that is fine, then suddenly is not, with nothing in the logs to explain the difference. An arm sweeps smoothly and judders once near the same part of its path. A rover tracks a line for a minute and then cuts a corner. A gripper closes a fraction late and knocks the cup over rather than picking it up. A balancing robot stays upright and then takes an unnecessary step. The tell is always the same: the fault is not reproducible on demand, it changes when you add logging to catch it, and the code involved is code you have read many times and know to be correct. Not all jitter matters, and this is the part beginners get wrong in the other direction. A stuttering video preview, a status message arriving in bursts, a screen that updates unevenly — none of that touches the machine's behaviour, and tightening the timing behind it buys you nothing. Jitter matters exactly where something is moving while the software is late.
What do you give up by chasing steady timing?
You give up flexibility, and more of it than most guides admit. A loop that must keep time cannot allocate memory freely, cannot write logs whenever it likes, cannot call a library that occasionally takes its time, and cannot be casually extended by adding one more thing to the end. Adding a feature stops being a five-minute edit and becomes a question of where the work can safely live. You often give up your comfortable language for the part that must keep the rhythm, which means either learning another one or accepting a boundary in your codebase. You give up some debugging convenience, because the tools that let you inspect a running program are themselves a source of the delay you are trying to remove. And you give up hours, which is the cost that actually stops projects. Every one of these is worth paying when a machine can hurt itself or someone else by being late. None of them is worth paying for a rover that bumps a skirting board.
When is ROS 2 the better choice?
ROS 2 is the better choice whenever the value of your robot lies in work other people have already done. A machine that has to build a map of a room and drive to a chosen point is a ROS 2 project, because mapping and navigation packages represent years of effort that nobody reproduces in evenings. If the sensor you bought ships only a ROS 2 driver, that decides it. ROS 2 also wins when your robot spans more than one computer, when you want to record a run and replay it later — which is one of the most useful debugging habits in robotics — and when you are heading toward a job or a lab where ROS 2 is the shared language. HORUS is not the answer for those projects, and picking it there means rebuilding plumbing you could have inherited. It is also worth saying plainly that ROS 2 is not the reason most beginner robots stutter; a loop full of logging on a hot small board is a far more likely culprit than the framework carrying the messages.
Is jitter just latency measured a different way?
No, and here is why: they are two separate quantities, and a robot can be excellent at one while being terrible at the other. A machine can take a comparatively long time to react and still be pleasant to work with, provided it takes the same long time every cycle, because you can build that delay into your expectations and the robot behaves the way the code says it will. The same machine can react quickly on average and be unusable, because one cycle in a hundred takes far longer than the rest and that is the cycle where the arm was already moving. This is why chasing the average is a trap. An average hides its own worst case, and the worst case is what breaks things — the one late reading, the one pause while memory was tidied, the one moment the network retried. When somebody tells you a system is fast, ask not how fast on average but how bad the slowest cycle gets, because that is what your robot lives with.
Will switching middleware make your robot deterministic?
Partly, but not the way you think. Changing what carries your messages removes one source of run-to-run variation, and on a machine where programs were serialising data and crossing the network to talk, that can be a large source. What it does not touch is everything else, and everything else is most of it. Your operating system decides which program runs at which moment, and that decision differs between runs. Your sensors return slightly different readings from an identical scene. Threads inside your own program interleave differently. Floating-point work summed in a different order gives a marginally different answer, which a control law can amplify into a visibly different path. Determinism is a property of the whole system, not a feature you install, and no middleware grants it on its own. What good plumbing buys you is a smaller pile of things to rule out when you go looking, which matters enormously when your robot behaves differently every run and you are trying to work out why.
How do you decide which of the three to work on first?
Work on whichever one your robot is showing you, and the symptom tells you which without any measurement. Run the machine and watch. If it is consistently late in the same way, you have latency, and the fix is to remove work from the path or to act earlier in your own code. If it is fine most of the time and wrong at unpredictable moments, you have jitter, and the fix is to find the step that occasionally takes longer — usually storage, the network, or a program pushed aside by the operating system. If two runs of the same task end differently, you have a determinism problem, and the first move is to reduce the number of moving parts until the difference disappears. Do not start with the framework. Start with what is inside your loop, because that is where beginners find the fault almost every time.
- If your robot is consistently late -> tune your own code, because a constant delay is something you can design around.
- If your robot is late at random -> hunt the occasional slow step, because that is jitter and no framework hides it.
- If you need mapping, navigation or a vendor driver -> ROS 2, because those packages are the project.
- If a Python program and a timed loop must share data on one computer -> a shared-memory middleware, because that boundary is the expensive one.
- If nothing visibly goes wrong -> leave the timing alone, because steadier timing you cannot observe is not worth the flexibility it costs.
When two options stay close, weigh them on the five axes of the HORUS Fit Framework — ecosystem size, setup effort, team size fit, deployment target, and licence — and choose the one that loses on the fewest. Five plain questions about your situation, no scores and no numbers. And when your robot does grow into the kind of machine where these three words start to matter, star HORUS on GitHub so it is in your list when you start building.