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
| Issue | Fix |
|---|---|
numpy install fails (compilation) | Use pip install numpy on aarch64 (wheels available for Pi 4+) |
scipy takes 30+ min to install | Use apt install python3-scipy instead of pip |
opencv-python fails | Use 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
- Deployment Guide — General deployment (Rust + Python)
- Real Hardware Recipe — I2C + serial examples
- GIL & Performance — Performance considerations
- Linux RT Setup — PREEMPT_RT, CPU isolation, permissions