Python Deployment

How to get your Python HORUS nodes running on a real robot.


Virtual Environments

horus run manages Python virtual environments automatically via .horus/:

# First run creates .horus/venv and installs dependencies from horus.toml
horus run src/main.py

# Dependencies declared in horus.toml [dependencies] with source = "pypi"
# are installed into .horus/venv automatically

For manual venv management:

python3 -m venv .venv
source .venv/bin/activate
pip install horus smbus2 pyserial numpy
python src/main.py

Docker

FROM python:3.12-slim

# Install system deps for hardware access
RUN apt-get update && apt-get install -y \
    i2c-tools \
    && rm -rf /var/lib/apt/lists/*

# Install HORUS
RUN curl -fsSL https://horusrobotics.dev/install | bash

# Install Python deps
COPY horus.toml .
RUN pip install smbus2 pyserial numpy

# Copy project
COPY src/ src/

# Run
CMD ["horus", "run", "src/main.py"]
# Build
docker build -t my-robot .

# Run with hardware access
docker run --rm \
    --device /dev/i2c-1 \
    --device /dev/ttyUSB0 \
    --cap-add SYS_NICE \
    my-robot

Key flags:

  • --device /dev/i2c-1 — I2C bus access
  • --device /dev/ttyUSB0 — Serial port access
  • --cap-add SYS_NICE — RT scheduling permissions
  • --privileged — Full hardware access (use only if needed)

systemd Service

Auto-start your robot on boot:

# /etc/systemd/system/my-robot.service
[Unit]
Description=My Robot HORUS Node
After=network.target

[Service]
Type=simple
User=robot
WorkingDirectory=/home/robot/my-robot
ExecStart=/home/robot/.cargo/bin/horus run src/main.py
Restart=on-failure
RestartSec=5
Environment=PYTHONPATH=/home/robot/my-robot

# RT scheduling permissions
AmbientCapabilities=CAP_SYS_NICE
LimitRTPRIO=99
LimitMEMLOCK=infinity

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable my-robot
sudo systemctl start my-robot
sudo journalctl -u my-robot -f  # View logs

ARM Platforms

Raspberry Pi

# Install HORUS
curl -fsSL https://horusrobotics.dev/install | bash

# NumPy wheels are available for Pi 4/5 (aarch64)
pip install numpy

# I2C access
sudo apt install i2c-tools python3-smbus
sudo usermod -aG i2c $USER

# GPIO access (for direct GPIO, not via horus drivers)
pip install RPi.GPIO  # or gpiod for modern interface

NVIDIA Jetson

# NumPy + CUDA pre-installed on JetPack
# PyTorch available via NVIDIA's wheel index:
pip install torch --index-url https://pypi.ngc.nvidia.com

# Install HORUS
curl -fsSL https://horusrobotics.dev/install | bash

Common ARM Issues

IssueFix
numpy install fails (compilation)Use pip install numpy on aarch64 (wheels available for Pi 4+)
scipy takes 30+ min to installUse apt install python3-scipy instead of pip
opencv-python failsUse apt install python3-opencv or pip install opencv-python-headless
Permission denied on /dev/i2c-*sudo usermod -aG i2c $USER then re-login
Permission denied on /dev/ttyUSB*sudo usermod -aG dialout $USER then re-login

Mixed Rust + Python Deployment

For robots with both Rust and Python nodes, use a launch file:

# launch.yaml
nodes:
  - name: motor_driver
    command: "horus run src/motor.rs"
    rate_hz: 1000

  - name: ml_detector
    command: "horus run src/detector.py"
    rate_hz: 30
    depends_on: [motor_driver]
horus launch launch.yaml

Both processes share topics via shared memory — zero-copy between Rust and Python.


Freeze Dependencies

Pin exact versions for reproducible deploys:

# Generate lockfile from horus.toml
horus lock

# Or with pip
pip freeze > requirements.txt

See Also