Deploy to Your Robot
This guide walks through every step from "my project works on my PC" to "it's running on my robot." No prior SSH or networking experience required.
Problem Statement
Your HORUS project runs on your development machine and you need to transfer it to a physical robot (Raspberry Pi, Jetson, or other Linux board) and run it there.
When To Use
- First-time deployment to a new robot
- Setting up SSH key authentication for passwordless deploys
- Configuring named deploy targets for repeated deployments
- Deploying to a fleet of multiple robots at once
Prerequisites
- A working HORUS project on your development PC
- A Linux-based robot (Raspberry Pi, Jetson, or any ARM/x86 board)
- Both machines on the same network (WiFi or Ethernet)
How It Works
horus deploy is a three-step pipeline that runs on your development PC:
Your code is compiled on your PC and the finished binary is copied to the robot. The robot just runs it.
What Each Machine Needs
Your Development PC
| Requirement | Why | How to install |
|---|---|---|
| HORUS CLI | Builds and deploys your project | Installation guide |
| Rust toolchain | Cross-compiles for robot architecture | Installed with HORUS |
| rsync | Syncs files to robot efficiently | sudo apt install rsync (usually pre-installed) |
| SSH client | Connects to robot | sudo apt install openssh-client (usually pre-installed) |
Supported dev PC operating systems: Linux, macOS, WSL 2. Native Windows without WSL is not supported (no rsync/SSH).
Your Robot
| Requirement | Why |
|---|---|
| Linux | Any distribution (Raspberry Pi OS, Ubuntu, Debian, etc.) |
| SSH server enabled | So your PC can connect and copy files |
| Network connection | WiFi or Ethernet, same network as your PC |
The robot does NOT need: HORUS, Rust, cargo, or any build tools. The compiled binary is self-contained.
Exception for Python projects: The robot also needs python3 and the HORUS Python package:
# Run this ON the robot (one-time setup)
pip install horus-robotics
Step-by-Step
Step 1: Prepare Your Robot
If you have a new Raspberry Pi or Jetson that isn't set up yet:
Raspberry Pi:
- Download Raspberry Pi Imager on your PC
- Flash an SD card with Raspberry Pi OS (or Ubuntu Server)
- In the imager settings (gear icon), configure:
- Username and password (e.g.,
pi/yourpassword) - WiFi network name and password
- Enable SSH (check the box)
- Username and password (e.g.,
- Insert the SD card into the Pi and power it on
- Wait 1-2 minutes for it to boot and connect to WiFi
Jetson Nano/Xavier/Orin:
- Flash the SD card or eMMC with NVIDIA JetPack (Ubuntu-based)
- Complete the first-boot setup (username, password, WiFi)
- SSH is enabled by default on JetPack
Any other Linux board:
- Ensure SSH is enabled:
sudo systemctl enable ssh && sudo systemctl start ssh - Ensure it's connected to the same network as your PC
Step 2: Find Your Robot's IP Address
Your PC and robot must be on the same network (same WiFi or same Ethernet switch). You need the robot's IP address to connect.
Option A: mDNS (easiest, try this first)
Most Linux boards advertise their hostname on the local network:
# On your PC:
ping raspberrypi.local # Raspberry Pi default hostname
ping jetson.local # Jetson default hostname
If it responds, you can use raspberrypi.local instead of an IP address:
horus deploy pi@raspberrypi.local --run
Option B: Check your router
- Open your router's admin page in a browser (usually
192.168.1.1or192.168.0.1) - Look for "Connected Devices" or "DHCP Clients"
- Find your robot's hostname (e.g., "raspberrypi") and note its IP
Option C: Scan your network
# On your PC — scan for all devices:
nmap -sn 192.168.1.0/24
# Or if your network is 192.168.0.x:
nmap -sn 192.168.0.0/24
Look for your robot's hostname or MAC address in the results.
Option D: Connect a monitor to the robot
Plug a monitor and keyboard into the robot and run:
hostname -I
# Output: 192.168.1.50
Step 3: Test SSH Connection
Before deploying, verify you can connect to the robot:
ssh pi@192.168.1.50
# Enter your password when prompted
Replace pi with your robot's username and 192.168.1.50 with the IP you found. If you see the robot's terminal prompt, it works. Type exit to disconnect.
If "Connection refused": SSH is not enabled on the robot. Connect a monitor and keyboard to the robot and run:
sudo systemctl enable ssh
sudo systemctl start ssh
Step 4: Set Up SSH Keys (Recommended)
Without SSH keys, horus deploy will prompt for your password during every deployment. Setting up keys makes it passwordless:
# On your PC — generate a key (press Enter for all prompts):
ssh-keygen -t ed25519
# Copy it to the robot:
ssh-copy-id pi@192.168.1.50
# Enter your password one last time
# Verify — this should connect WITHOUT asking for a password:
ssh pi@192.168.1.50
Step 5: Deploy
In your project directory on your PC:
horus deploy pi@192.168.1.50 --run
You'll see:
HORUS Deploy
Target: pi@192.168.1.50
Remote dir: ~/horus_deploy
Architecture: ARM64 (aarch64)
Build mode: release
Run after: true
Step 1: Building project...
Checking target aarch64-unknown-linux-gnu... OK
Building for ARM64 (aarch64)...
Build complete
Step 2: Syncing files to target...
Will sync '/home/you/my-robot' to pi@192.168.1.50:~/horus_deploy/ (with --delete)
Files on remote not present locally will be DELETED
Continue? [y/N] y
Syncing files...
Files synced
Step 3: Running on target...
Running: ./target/aarch64-unknown-linux-gnu/release/my_robot
Press Ctrl+C to stop
[SCHEDULER] Started with 3 nodes at 100 Hz
[motor_controller] Initialized
...
The binary is self-contained. The robot doesn't need Rust or cargo installed.
Press Ctrl+C to stop the robot.
Step 6: Save Your Target
Typing the full pi@192.168.1.50 every time gets tedious. Create a deploy.yaml file in your project root:
targets:
robot:
host: pi@192.168.1.50
arch: aarch64
Now deploy with just a name:
horus deploy robot --run
For multiple robots, add more targets:
targets:
robot:
host: pi@192.168.1.50
arch: aarch64
jetson:
host: nvidia@jetson.local
arch: aarch64
port: 2222
identity: ~/.ssh/jetson_key
arm-pc:
host: ubuntu@10.0.0.20
arch: x86_64
dir: ~/my_app
Deploy Options
| Option | What it does | Example |
|---|---|---|
--run | Execute the binary after deploying | horus deploy robot --run |
--dry-run | Show what would happen without doing it | horus deploy robot --dry-run |
--arch | Override target architecture | horus deploy robot --arch armv7 |
--debug | Build in debug mode (faster build, slower binary) | horus deploy robot --debug |
-d, --dir | Custom remote directory (default: ~/horus_deploy) | horus deploy robot -d /opt/robot |
-p, --port | Custom SSH port (default: 22) | horus deploy robot -p 2222 |
-i, --identity | SSH private key file | horus deploy robot -i ~/.ssh/robot_key |
--all | Deploy to every target in deploy.yaml | horus deploy --all --run |
--list | Show configured targets | horus deploy --list |
Fleet Deployment
Deploy to all robots with one command:
horus deploy --all --run
This builds once and syncs to each robot. If one robot is unreachable, the others still get deployed:
HORUS Fleet Deploy (3 targets)
1. robot -> pi@192.168.1.50
2. jetson -> nvidia@jetson.local
3. arm-pc -> ubuntu@10.0.0.20
Step 1: Building for ARM64 (shared across 3 targets)...
Build complete
Step 2: Syncing to 3 targets...
This will sync to 3 remote hosts (with --delete)
Continue? [y/N] y
--- [1/3] robot
Files synced
[1/3] robot done
--- [2/3] jetson
[2/3] jetson done
--- [3/3] arm-pc
[x] arm-pc failed: SSH connection refused
=== Fleet Deploy Summary
2/3 targets deployed successfully
What Gets Copied to the Robot
The project directory is synced to ~/horus_deploy/ on the robot, excluding:
target/(build artifacts — only the final binary is kept).git/(version control history)__pycache__/and*.pyc(Python cache)node_modules/(JavaScript dependencies)
The rsync --delete flag keeps the remote directory in sync — files you delete locally are also deleted on the robot.
Architecture Auto-Detection
If you don't specify --arch, horus guesses from the hostname:
| Hostname contains | Detected architecture |
|---|---|
jetson, nano, xavier, orin | aarch64 |
pi4, pi5, raspberry | aarch64 |
pi3, pi2 | armv7 |
| Anything else | aarch64 (default) |
Override with --arch if the auto-detection is wrong:
horus deploy myrobot@10.0.0.5 --arch x86_64
Rust vs Python Differences
| Aspect | Rust project | Python project |
|---|---|---|
| Build step | Cross-compiles for target architecture | Skipped (no compilation needed) |
| Robot requirements | Nothing beyond Linux + SSH | Python 3 + pip install horus-robotics |
| What runs on robot | Single binary (./target/.../my_robot) | python3 src/main.py |
| Binary size | Self-contained (~5-50 MB) | Source files only |
| First deploy speed | Slower (compilation) | Faster (just file sync) |
Auto-Start on Boot (systemd)
To run your HORUS project automatically when the robot boots, create a systemd service:
# On the robot, create a service file:
sudo tee /etc/systemd/system/horus-robot.service << 'EOF'
[Unit]
Description=HORUS Robot Application
After=network.target
[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/horus_deploy
ExecStart=/home/pi/horus_deploy/target/aarch64-unknown-linux-gnu/release/my_robot
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable horus-robot
sudo systemctl start horus-robot
# Check status
sudo systemctl status horus-robot
# View logs
journalctl -u horus-robot -f
Troubleshooting
"Connection refused" when deploying
SSH is not enabled or not running on the robot:
# Connect a monitor/keyboard to the robot and run:
sudo systemctl enable ssh
sudo systemctl start ssh
"Permission denied (publickey)"
The robot is rejecting your SSH key or password:
# Try with explicit password authentication:
ssh -o PreferredAuthentications=password pi@192.168.1.50
# If that works, re-copy your key:
ssh-copy-id pi@192.168.1.50
"rsync: command not found"
Install rsync on your development PC:
# Ubuntu/Debian:
sudo apt install rsync
# macOS:
brew install rsync
Binary crashes or "Exec format error" on robot
Wrong architecture. The binary was compiled for a different CPU than the robot has:
# Check what the robot actually runs:
ssh pi@192.168.1.50 "uname -m"
# aarch64 = use --arch aarch64
# armv7l = use --arch armv7
# x86_64 = use --arch x86_64
# Re-deploy with the correct architecture:
horus deploy pi@192.168.1.50 --arch armv7 --run
"cargo build failed" during cross-compilation
The cross-compilation target may not be installed. Horus installs it automatically, but if it fails:
# Install manually on your PC:
rustup target add aarch64-unknown-linux-gnu
# For ARM 32-bit:
rustup target add armv7-unknown-linux-gnueabihf
You may also need the cross-compilation linker:
# Ubuntu/Debian:
sudo apt install gcc-aarch64-linux-gnu
# For ARM 32-bit:
sudo apt install gcc-arm-linux-gnueabihf
"ping raspberrypi.local" doesn't work
mDNS may not be available. Try:
# Install mDNS support on your PC:
sudo apt install avahi-utils
# Install on the robot (connect monitor/keyboard):
sudo apt install avahi-daemon
Or skip mDNS and find the IP through your router or nmap instead.
Deploy works but program doesn't find hardware (GPIO, serial, I2C)
The robot user may not have permission to access hardware devices:
# On the robot:
sudo usermod -aG dialout,gpio,i2c,spi pi
# Log out and back in for changes to take effect
See Also
- Operations Overview — Quick reference for all operations commands
- RT Setup — RT kernel, safety monitoring, and performance tuning
- CLI Reference — Full
horus deployflag reference