Real-Time Tuning

HORUS handles real-time automatically. Set your rate, HORUS does the rest:

horus.run(Node(tick=my_controller, rate=1000))

No configuration needed. HORUS auto-detects your system's RT capabilities and uses the best available: SCHED_FIFO priority, memory locking, CPU pinning, lock-free IPC — all built in. No external packages required.

This page covers optional tuning for users who want the lowest possible jitter.


Check Your System

horus doctor

The Real-Time section shows what HORUS detected:

Real-Time
  ✓ PREEMPT_RT active, jitter ±10μs

  or

  ⚠ Standard kernel, jitter ±100μs (run `horus setup-rt` for ±20μs)

For detailed RT status:

horus setup-rt --check
HORUS Real-Time Setup

  Kernel: Linux 6.8.0-generic
  ⚠ PREEMPT_RT: not detected
  ✓ SCHED_FIFO: available (priority 1-99)
  ⚠ Memory locking: limited
  ℹ CPU cores: 8
  ℹ Isolated CPUs: none
  ℹ Estimated jitter: ±100μs

Install RT Kernel (Optional)

If you need tighter timing (force control, high-bandwidth servo loops):

sudo horus setup-rt

This command:

  1. Detects your Linux distribution (Ubuntu, Debian, Fedora, Arch)
  2. Installs the RT kernel package from your distro's repository
  3. Configures memory lock limits (/etc/security/limits.d/99-horus-rt.conf)
  4. Suggests CPU core isolation for dedicated RT threads

Requires a reboot after install. Run horus setup-rt --check to verify.

To undo: sudo horus setup-rt --undo


Expected Performance

SetupJitter (p99)Good For
Standard Linux±200μsPosition control, ML policy deployment, navigation
+ RT kernel (horus setup-rt)±20-80μsForce control, humanoid balance, high-rate servos
+ CPU isolation±10-30μsHigh-bandwidth servo loops, multi-joint coordination

Most robots work fine without any tuning. The standard Linux setup handles position control, velocity control, ML policy deployment, and navigation at rates up to 1kHz.


What HORUS Does Automatically

When you set rate=1000, HORUS internally:

  • Detects if PREEMPT_RT is available and uses it
  • Sets SCHED_FIFO thread priority for RT nodes
  • Calls mlockall() to prevent page faults
  • Pre-faults 256KB of stack memory
  • Pins RT threads to isolated CPU cores (if available)
  • Sets budget to 80% of period (800μs for 1kHz)
  • Sets deadline to 95% of period (950μs for 1kHz)
  • Enables graduated watchdog (warn at 3 misses, isolate at 10, kill at 20)

You never need to configure any of this. Override only if you have specific requirements:

Node(
    tick=my_controller,
    rate=1000,              # 1kHz tick rate
    budget=300 * us,        # Override: 300μs budget (default: 800μs)
    core=6,                 # Override: pin to CPU 6
    on_miss="skip",         # Override: skip missed ticks (default: warn)
)

See Also