133 lines
5.1 KiB
Bash
Executable File
133 lines
5.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# run.sh — one-command launcher for Marcus on the Jetson.
|
|
#
|
|
# What it does (safely, in order):
|
|
# 1. Ensures systemd Ollama is running (with drop-in flags).
|
|
# 2. Pulls the VLM model if it's missing.
|
|
# 3. Runs the VLM warmup (asks you to put the robot in squat first).
|
|
# 4. Health-gates iGPU placement and system memory.
|
|
# 5. Pauses for you to stand the robot up.
|
|
# 6. Launches Marcus.
|
|
#
|
|
# Fail-fast: any health check failure aborts BEFORE the robot stands.
|
|
#
|
|
# Usage:
|
|
# ./run.sh normal launch
|
|
# ./run.sh --skip-warmup skip warmup (only safe if already warm)
|
|
# ./run.sh --skip-stand-prompt don't pause for stand-up confirmation
|
|
#
|
|
# First time on a fresh Jetson (one-time, not run here):
|
|
# sudo ./install_ollama_jetson.sh
|
|
|
|
set -e
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
cd "$SCRIPT_DIR"
|
|
|
|
SKIP_WARMUP=0
|
|
SKIP_STAND_PROMPT=0
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--skip-warmup) SKIP_WARMUP=1 ;;
|
|
--skip-stand-prompt) SKIP_STAND_PROMPT=1 ;;
|
|
-h|--help)
|
|
grep '^#' "$0" | sed 's/^# \{0,1\}//'
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown argument: $arg" >&2
|
|
echo "Use --help for usage." >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# ── tiny color helpers ──────────────────────────────────────────────
|
|
BOLD='\033[1m'; GREEN='\033[32m'; YELLOW='\033[33m'; RED='\033[31m'; DIM='\033[2m'; OFF='\033[0m'
|
|
step() { echo -e "\n${BOLD}▶ $1${OFF}"; }
|
|
ok() { echo -e " ${GREEN}✓${OFF} $1"; }
|
|
warn() { echo -e " ${YELLOW}⚠${OFF} $1"; }
|
|
die() { echo -e " ${RED}✗${OFF} $1"; exit 1; }
|
|
|
|
MODEL=$(python3 -c "import json; print(json.load(open('Config/config_Brain.json'))['ollama_model'])")
|
|
HOST=$(python3 -c "import json; print(json.load(open('Config/config_Brain.json'))['ollama_host'])")
|
|
|
|
# ── 1. Ensure Ollama service is up ─────────────────────────────────
|
|
step "1/5 Ollama systemd service"
|
|
if ! systemctl is-active --quiet ollama; then
|
|
warn "service is not active — starting it"
|
|
sudo systemctl start ollama
|
|
sleep 2
|
|
fi
|
|
if ! systemctl is-active --quiet ollama; then
|
|
die "failed to start Ollama; check: systemctl status ollama"
|
|
fi
|
|
ADJUST=$(systemctl show ollama -p OOMScoreAdjust --value)
|
|
if [[ "$ADJUST" != "500" ]]; then
|
|
warn "OOMScoreAdjust is '$ADJUST' (expected 500)"
|
|
warn "drop-in may not be installed — run: sudo ./install_ollama_jetson.sh"
|
|
fi
|
|
ok "service active (OOMScoreAdjust=$ADJUST)"
|
|
|
|
# ── 2. Ensure the model is pulled ──────────────────────────────────
|
|
step "2/5 VLM model present"
|
|
if ! ollama list | awk 'NR>1 {print $1}' | grep -qx "$MODEL"; then
|
|
warn "$MODEL not in store — pulling (~2.2 GB, one-time)"
|
|
ollama pull "$MODEL"
|
|
fi
|
|
ok "$MODEL available in Ollama store"
|
|
|
|
# ── 3. Warmup (robot-in-squat safety banner lives inside the script) ──
|
|
step "3/5 VLM warmup"
|
|
if [[ $SKIP_WARMUP -eq 1 ]]; then
|
|
warn "skipped by --skip-warmup"
|
|
else
|
|
./warmup_vlm.sh "$MODEL"
|
|
fi
|
|
|
|
# ── 4. Health gates ────────────────────────────────────────────────
|
|
step "4/5 Health check"
|
|
|
|
# 4a. PROCESSOR placement
|
|
PS_LINE=$(ollama ps | awk -v m="$MODEL" '$1==m {for(i=1;i<=NF;i++) if($i ~ /GPU/) {print $(i-1), $i; exit}}')
|
|
PROCESSOR=$(ollama ps | awk -v m="$MODEL" 'NR>1 && $1==m {
|
|
for(i=4;i<=NF;i++) if($i=="GPU" || $i=="CPU/GPU" || $i=="CPU") {print $(i-1) " " $i; break}
|
|
}')
|
|
if [[ -z "$PROCESSOR" ]]; then
|
|
warn "model not loaded — running without prewarm; first vision call will cold-load"
|
|
elif echo "$PROCESSOR" | grep -qE "^100% GPU"; then
|
|
ok "placement: $PROCESSOR (ideal)"
|
|
elif echo "$PROCESSOR" | grep -qE "CPU/GPU"; then
|
|
SPLIT=$(echo "$PROCESSOR" | awk '{print $1}')
|
|
warn "placement: $PROCESSOR — partial CPU offload will slow vision queries"
|
|
warn "if unacceptable, lower OLLAMA_GPU_OVERHEAD in install_ollama_jetson.sh"
|
|
else
|
|
warn "placement: $PROCESSOR"
|
|
fi
|
|
|
|
# 4b. system memory
|
|
read -r MEM_USED MEM_AVAIL SWAP_USED <<< "$(free -m | awk '
|
|
/^Mem:/ { used=$3; avail=$7 }
|
|
/^Swap:/ { sused=$3 }
|
|
END { print used, avail, sused }
|
|
')"
|
|
echo " ${DIM}mem used: ${MEM_USED} MiB available: ${MEM_AVAIL} MiB swap used: ${SWAP_USED} MiB${OFF}"
|
|
if (( SWAP_USED > 500 )); then
|
|
die "swap in use (${SWAP_USED} MiB) — memory is already tight, would thrash under load"
|
|
fi
|
|
if (( MEM_AVAIL < 1000 )); then
|
|
die "only ${MEM_AVAIL} MiB available — Holosoma/Marcus/camera won't have room"
|
|
fi
|
|
ok "memory healthy"
|
|
|
|
# ── 5. Stand the robot, then launch ────────────────────────────────
|
|
step "5/5 Launch Marcus"
|
|
if [[ $SKIP_STAND_PROMPT -eq 0 ]]; then
|
|
echo -e " ${YELLOW}Robot can now stand up.${OFF}"
|
|
echo -e " ${DIM}Press ENTER when the robot is standing, or Ctrl-C to abort.${OFF}"
|
|
read -r
|
|
fi
|
|
echo
|
|
|
|
exec python3 run_marcus.py
|