Linux RT Setup
Real-time scheduling requires kernel and permission configuration. This guide walks through every step, from checking your current capabilities to verifying Horus runs with RT scheduling.
Check Current RT Capabilities
Before changing anything, check what your system already supports:
# Check if your kernel has PREEMPT_RT
uname -v | grep -i preempt
# Check your current RT priority limit (0 means no RT allowed)
ulimit -r
# Check if SCHED_FIFO works at all
chrt -f 1 echo "RT scheduling works"
If ulimit -r returns 0 or chrt fails with "Operation not permitted", follow the sections below.
Grant RT Permissions
Edit /etc/security/limits.conf to allow your user (or group) to use RT scheduling:
# Add to /etc/security/limits.conf
# Replace 'robotics' with your username or group (@groupname for groups)
robotics soft rtprio 99
robotics hard rtprio 99
robotics soft memlock unlimited
robotics hard memlock unlimited
Log out and back in for changes to take effect. Verify with ulimit -r — it should now return 99.
Install PREEMPT_RT Kernel
A standard kernel uses PREEMPT_VOLUNTARY or PREEMPT_DYNAMIC, which gives millisecond-scale worst-case latency. PREEMPT_RT brings that down to microseconds.
Ubuntu / Debian
sudo apt install linux-image-rt-amd64 # Debian
sudo apt install linux-lowlatency # Ubuntu (close to RT)
# For full PREEMPT_RT on Ubuntu:
sudo apt install linux-image-realtime # Ubuntu Pro / 24.04+
Reboot and select the RT kernel from GRUB. Verify:
uname -v
# Should contain "PREEMPT_RT" or "PREEMPT RT"
From Source (Any Distro)
Download the PREEMPT_RT patch from kernel.org/pub/linux/kernel/projects/rt, apply it to a matching kernel version, and build with CONFIG_PREEMPT_RT=y.
CPU Isolation
Isolate cores from the Linux scheduler so only your RT threads run on them. This eliminates scheduling jitter from other processes.
Add isolcpus to your kernel command line in /etc/default/grub:
# Isolate cores 2 and 3 for RT use
GRUB_CMDLINE_LINUX="isolcpus=2,3 nohz_full=2,3 rcu_nocbs=2,3"
Then sudo update-grub && sudo reboot. Verify with:
cat /sys/devices/system/cpu/isolated
# Should output: 2-3
Pin Horus nodes to isolated cores:
let mut scheduler = Scheduler::new()
.require_rt()
.cores(&[2, 3])
.tick_rate(1000_u64.hz());
Grant CAP_SYS_NICE
As an alternative to limits.conf, you can grant the RT capability directly to a binary:
sudo setcap cap_sys_nice=eip ./target/release/my_robot
This lets that specific binary use RT scheduling without root or limits.conf changes. Useful for deployment where you do not want blanket RT permissions.
Verify the Setup
# Run a program with SCHED_FIFO at priority 50
chrt -f 50 ./target/release/my_robot
# Check that it is actually running with RT scheduling
ps -eo pid,cls,rtprio,comm | grep my_robot
# Should show "FF" (FIFO) and priority 50
Horus RT Integration
.prefer_rt() vs .require_rt()
// Prefer RT: use RT if available, fall back to normal scheduling
let mut scheduler = Scheduler::new()
.prefer_rt()
.tick_rate(500_u64.hz());
// Require RT: panic at startup if RT is not available
let mut scheduler = Scheduler::new()
.require_rt()
.tick_rate(1000_u64.hz());
Use .prefer_rt() during development and .require_rt() in production when timing guarantees matter.
Checking Degradations
After building the scheduler, inspect whether RT was successfully acquired:
let scheduler = Scheduler::new()
.prefer_rt()
.tick_rate(500_u64.hz());
// After running, check status (includes any degradations)
println!("{}", scheduler.status());
If RT was requested but unavailable, a degradation entry will explain why (missing permissions, no PREEMPT_RT, etc).
Troubleshooting
"Operation not permitted" / "cannot set SCHED_FIFO"
- Check
ulimit -r— must be > 0 - Check that limits.conf changes are applied (requires re-login)
- Try
setcap cap_sys_nice=eipon the binary - If running in Docker: add
--cap-add SYS_NICEtodocker run
RT works but latency is high
- Verify
PREEMPT_RTkernel:uname -v | grep PREEMPT_RT - Check for isolated CPUs:
cat /sys/devices/system/cpu/isolated - Disable CPU frequency scaling:
cpupower frequency-set -g performance - Disable SMT/hyperthreading in BIOS for dedicated RT cores
Platform-Specific Notes
NVIDIA Jetson
Jetson runs a custom L4T kernel. PREEMPT_RT patches are available from NVIDIA for Jetson Orin and later. Apply them when building the kernel with the Jetson Linux BSP. isolcpus works — isolate the performance cores (typically 4-7 on Orin).
Raspberry Pi
Use the linux-image-rt package from the Raspberry Pi OS repo, or apply the PREEMPT_RT patch to the rpi-6.x.y kernel branch. The Pi 4/5 have 4 cores — isolating cores 2-3 for RT while leaving 0-1 for the OS works well. Set arm_freq in config.txt to a fixed value to avoid frequency scaling jitter.