diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 0000000..de980d3 --- /dev/null +++ b/deploy/README.md @@ -0,0 +1,87 @@ +# Argonaut 3 — Deploy Files + +This folder contains the systemd unit files and launch wrappers that live +OUTSIDE the ROS2 workspace on RPi5, version-controlled here so they are +recoverable. The files in this folder are copies — the authoritative +running copies are at the deploy locations noted below. + +--- + +## Files + +| Repo file | Deploy location on RPi5 | Purpose | +|---|---|---| +| `argonaut.service` | `/etc/systemd/system/argonaut.service` | Autonomy stack service unit | +| `argonaut-stack.sh` | `/usr/local/bin/argonaut-stack.sh` (chmod +x) | Autonomy stack launch wrapper | +| `argonaut-api.service` | `/etc/systemd/system/argonaut-api.service` | FastAPI backend service unit | +| `argonaut-api.sh` | `/usr/local/bin/argonaut-api.sh` (chmod +x) | FastAPI backend launch wrapper | + +Also required (NOT stored here — contains environment specifics): +`/etc/argonaut/rov.env` — EnvironmentFile for argonaut.service: +``` +ENV=dev +BLUEOS_IP=192.168.1.100 +RECORD=true +``` + +--- + +## Python dependencies (RPi5) + +The FastAPI backend (`rov_api`) requires fastapi and uvicorn installed +system-wide so they resolve regardless of which user runs the service: + +``` +sudo pip3 install fastapi uvicorn --break-system-packages --ignore-installed typing_extensions +``` + +The `--ignore-installed typing_extensions` flag is required because the +Debian-managed `typing_extensions` package has no pip RECORD file and +cannot be uninstalled by pip; ignoring it lets the install complete while +leaving the Debian package in place. + +Confirmed working versions: fastapi 0.139.0, uvicorn 0.50.0. + +--- + +## Install / re-deploy procedure + +From this repo folder on RPi5: + +``` +sudo cp deploy/argonaut.service /etc/systemd/system/argonaut.service +sudo cp deploy/argonaut-api.service /etc/systemd/system/argonaut-api.service +sudo cp deploy/argonaut-stack.sh /usr/local/bin/argonaut-stack.sh +sudo cp deploy/argonaut-api.sh /usr/local/bin/argonaut-api.sh +sudo chmod +x /usr/local/bin/argonaut-stack.sh /usr/local/bin/argonaut-api.sh +sudo systemctl daemon-reload +``` + +--- + +## Service management + +DEV POLICY: both services are installed but NOT enabled-on-boot. +Start manually (verify BlueOS heartbeat before starting the stack): + +``` +sudo systemctl start argonaut.service +sudo systemctl start argonaut-api.service +``` + +Field readiness — enable on boot only when field-ready: + +``` +sudo systemctl enable argonaut.service +sudo systemctl enable argonaut-api.service +``` + +--- + +## Notes + +- `/home/ubuntu/ros2_ws` is a symlink to `/data/ros2_ws` (NVMe data drive). + Both wrappers rely on this — do not remove the symlink. +- `argonaut-api.service` orders After=argonaut.service but does not Require + it, so the API can start independently for /health checks. Mission + commands return a clear "service unavailable" error if the stack is down. diff --git a/deploy/argonaut-api.service b/deploy/argonaut-api.service new file mode 100644 index 0000000..461e8fb --- /dev/null +++ b/deploy/argonaut-api.service @@ -0,0 +1,33 @@ +# argonaut-api.service — Argonaut 3 FastAPI backend +# +# HTTP bridge from Cockpit widgets to the ROS2 autonomy stack (port 8081). +# Endpoints: /health, /abort (W3 RETURN TO SAFE), /mission/start, /mission/stop. +# +# DEPLOY LOCATION: /etc/systemd/system/argonaut-api.service +# +# DEV POLICY (matches argonaut.service): +# Installed but NOT enabled-on-boot. Start manually: +# sudo systemctl start argonaut-api.service +# When field-ready, enable on boot: +# sudo systemctl enable argonaut-api.service +# +# Soft ordering After=argonaut.service so the ROS2 graph is up first, but +# no hard Requires= — the API can still start for /health checks if the +# stack is down (mission commands then return a clear "unavailable" error). + +[Unit] +Description=Argonaut 3 FastAPI backend (HTTP -> ROS2 bridge) +After=network-online.target argonaut.service +Wants=network-online.target + +[Service] +Type=simple +User=ubuntu +Group=ubuntu +WorkingDirectory=/data/ros2_ws +ExecStart=/usr/local/bin/argonaut-api.sh +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target diff --git a/deploy/argonaut-api.sh b/deploy/argonaut-api.sh new file mode 100755 index 0000000..9bdde56 --- /dev/null +++ b/deploy/argonaut-api.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# +# argonaut-api.sh — launch wrapper for the Argonaut 3 FastAPI backend. +# +# DEPLOY LOCATION: /usr/local/bin/argonaut-api.sh (chmod +x) +# +# systemd does NOT read ~/.bashrc, so ROS2 and the workspace overlay must +# be sourced explicitly here before running the node. Mirrors the +# argonaut-stack.sh wrapper used by argonaut.service. +# +# Sourcing order: base ROS2 Jazzy first, then the workspace overlay so +# rov_interfaces and rov_api resolve from the local build. + +set -e + +# Base ROS2 Jazzy environment +source /opt/ros/jazzy/setup.bash + +# Workspace overlay (rov_interfaces, rov_api, etc.) +# Note: /home/ubuntu/ros2_ws is a symlink to /data/ros2_ws (NVMe data drive). +source /data/ros2_ws/install/setup.bash + +# Run the FastAPI backend node. exec replaces the shell so systemd tracks +# the Python process directly (correct signal handling on stop/restart). +exec ros2 run rov_api api_node diff --git a/deploy/argonaut-stack.sh b/deploy/argonaut-stack.sh new file mode 100755 index 0000000..aa1836a --- /dev/null +++ b/deploy/argonaut-stack.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# +# argonaut-stack.sh — Argonaut 3 autonomy stack launcher (called by systemd). +# +# DEPLOY LOCATION: /usr/local/bin/argonaut-stack.sh (chmod +x) +# +# systemd does NOT read ~/.bashrc, so ROS2 and the workspace overlay must +# be sourced explicitly. Reads ENV, BLUEOS_IP, RECORD from the systemd +# EnvironmentFile (/etc/argonaut/rov.env). +# +# Note: /home/ubuntu/ros2_ws is a symlink to /data/ros2_ws (NVMe data drive), +# so this path resolves correctly to the workspace on the NVMe. + +set -e + +# Base ROS2 Jazzy environment +source /opt/ros/jazzy/setup.bash + +# Workspace overlay (via /home/ubuntu/ros2_ws symlink -> /data/ros2_ws) +source /home/ubuntu/ros2_ws/install/setup.bash + +# Launch the full autonomy stack with environment-driven parameters. +# exec replaces the shell so systemd tracks the launch process directly. +exec ros2 launch rov_bringup rov_full.launch.py \ + env:=${ENV} blueos_ip:=${BLUEOS_IP} record:=${RECORD} diff --git a/deploy/argonaut.service b/deploy/argonaut.service new file mode 100644 index 0000000..edffee5 --- /dev/null +++ b/deploy/argonaut.service @@ -0,0 +1,30 @@ +# argonaut.service — Argonaut 3 Autonomy Stack +# +# Launches the full ROS2 autonomy stack via rov_bringup rov_full.launch.py. +# +# DEPLOY LOCATION: /etc/systemd/system/argonaut.service +# +# DEV POLICY: +# Installed but NOT enabled-on-boot. Start manually after verifying the +# BlueOS heartbeat: +# sudo systemctl start argonaut.service +# When field-ready, enable on boot: +# sudo systemctl enable argonaut.service +# +# Reads environment (ENV, BLUEOS_IP, RECORD) from /etc/argonaut/rov.env. + +[Unit] +Description=Argonaut 3 Autonomy Stack +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=ubuntu +EnvironmentFile=/etc/argonaut/rov.env +ExecStart=/usr/local/bin/argonaut-stack.sh +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target