Real-Time Linux on Raspberry Pi: PREEMPT_RT for Low-Latency GPIO and Motor Control
Our LinuxCNC on a Raspberry Pi guide covers one specific, well-trodden application of real-time Linux: motion control offloaded to a Mesa Ethernet card, with LinuxCNC's own real-time layer doing the timing-critical work. This guide is broader — it covers PREEMPT_RT itself, the real-time kernel patch that any Raspberry Pi project can use, and why you'd reach for it any time you're writing your own GPIO-driven control loop for something that cares about consistent, low-jitter timing: bit-banged stepper drivers, precise PWM generation, closed-loop feedback control, or any project where "usually fast enough" isn't good enough.
Why Stock Raspberry Pi OS Isn't Real-Time
Standard Raspberry Pi OS runs a normal preemptible Linux kernel, which is good at overall throughput but makes no promises about how long any individual task might have to wait before running. A GPIO toggle in a Python or C program can, in the worst case, get delayed by milliseconds while the kernel services a network interrupt, a filesystem operation, or another higher-priority process — normally invisible, but devastating for anything that needs a repeatable, tight timing window. If you've ever bit-banged a protocol from user-space GPIO calls and seen occasional glitches or jitter that a hardware peripheral (like the Pi's dedicated PWM or SPI hardware) doesn't show, that's this exact problem: the standard kernel scheduler prioritizing overall system responsiveness over hard timing guarantees for any single task.
What PREEMPT_RT Actually Changes
Kernel BehaviorStock KernelPREEMPT_RT Kernel Interrupt handlersRun at high priority, can block other work for their full durationConverted to preemptible kernel threads, can themselves be interrupted by higher-priority real-time tasks SpinlocksNon-preemptible — a task holding one can't be interruptedMostly converted to preemptible mutexes Worst-case scheduling latencyCan spike into multiple milliseconds under loadTypically held under 50-100 microseconds even under load, on a Pi 4/5 SCHED_FIFO / SCHED_RR priorityAvailable but less meaningful given aboveActually delivers on its promise — a high-priority real-time thread genuinely preempts almost everything elseThe tradeoff is modest average-case throughput loss (the extra preemption points and lock conversions add a small amount of overhead) in exchange for dramatically better worst-case latency — exactly the swap you want for a control loop, and exactly the wrong swap for something like video transcoding where average throughput matters more than any single frame's timing.
Installing PREEMPT_RT on Raspberry Pi OS
As of recent Raspberry Pi OS releases, a PREEMPT_RT-patched kernel is available directly through apt for Pi 4 and Pi 5 boards, which is a much simpler path than the old build-your-own-kernel process:
sudo apt update sudo apt install linux-image-rpi-v8-rt # 64-bit Pi 4 sudo apt install linux-image-rpi-2712-rt # Pi 5 sudo rebootAfter rebooting, confirm the real-time kernel is actually active:
uname -a # Look for "PREEMPT_RT" in the output string cat /sys/kernel/realtime # Should print 1If you're on an older Pi model or a Raspberry Pi OS version without a prebuilt RT kernel package available, the fallback is compiling the kernel yourself against the matching PREEMPT_RT patch series from the kernel.org real-time tree — a longer process involving cross-compilation and manual kernel/module installation that's well documented in the Raspberry Pi kernel-building guides, but the prebuilt package route above should cover most current Pi 4/5 setups.
Writing Software That Actually Uses It
Installing the RT kernel alone doesn't automatically make your program real-time — a normal-priority process still competes with everything else on the system. To get the benefit, your timing-critical thread needs to explicitly request a real-time scheduling policy and priority, and should lock its memory to prevent page faults from introducing latency:
#include <sched.h> #include <sys/mman.h> struct sched_param param; param.sched_priority = 80; // 1-99, higher = more priority sched_setscheduler(0, SCHED_FIFO, ¶m); mlockall(MCL_CURRENT | MCL_FUTURE); // prevent memory from being swapped outIn Python, the same effect is available through the os.sched_setscheduler() call, though for genuinely tight timing (sub-millisecond) you'll generally get more consistent results from C than from Python's interpreter overhead — Python is fine for a control loop with millisecond-scale requirements, less so for one needing single-digit microsecond consistency.
Practical Tuning Beyond the Kernel Patch
- Isolate a CPU core with the isolcpus kernel boot parameter so your real-time thread has a core with minimal other scheduling activity competing for it.
- Disable CPU frequency scaling (set the governor to performance) — frequency transitions themselves introduce timing variability.
- Pin your real-time thread to the isolated core with sched_setaffinity() or the taskset command.
- Disable unnecessary services that generate periodic interrupts or scheduling activity you don't need running (Bluetooth, unused network services) if they're not part of your project.
- Use hardware peripherals over bit-banging wherever possible — the Pi's dedicated PWM, SPI, and I2C hardware blocks don't need CPU-level real-time guarantees at all, because the timing-critical part happens in silicon, not in your scheduled code. PREEMPT_RT matters most for the cases hardware peripherals can't cover.
When You Actually Need This
Use CaseNeed PREEMPT_RT? Reading an I2C sensor every secondNo — timing tolerance is enormous relative to any jitter Driving stepper motors via bit-banged GPIO step pulsesYes, or better yet use dedicated step/dir hardware — jitter directly causes missed steps or uneven motion A PID control loop closing at a fixed 1kHz rateYes — loop timing consistency directly affects control stability Serving a web dashboard, reading MQTT messagesNo — not remotely timing-critical Audio synthesis/DSP with tight buffer deadlinesOften yes — audio dropouts are a direct, audible symptom of missed real-time deadlinesPREEMPT_RT is not a magic performance upgrade — for the large majority of Raspberry Pi projects that read a sensor occasionally or serve a web page, it does nothing useful and just adds a small average-case overhead for no benefit. But for the specific category of project where your code has to reliably do something at a fixed cadence with minimal jitter — motor control, precision timing, low-latency audio — it's the difference between "works great on the bench and glitches under load" and something you can actually trust in production.
Related Guides
- How to Control GPIO Pins on Raspberry Pi with Python
- Automated Plant Watering System with Raspberry Pi
- Controlling GPIO Outputs with Python — LED, Relay, and Buzzer
- Raspberry Pi GPIO: Complete Beginner Guide with Python Examples
- Getting Started with ROS2 on Raspberry Pi for Robotics
- How to Install Klipper on Any 3D Printer: Complete Setup Guide