Skip to content

Instantly share code, notes, and snippets.

@raghavauppuluri13
Last active October 21, 2025 16:50
Show Gist options
  • Save raghavauppuluri13/62eb0db4c162e6fa77a654fcce17609b to your computer and use it in GitHub Desktop.
Save raghavauppuluri13/62eb0db4c162e6fa77a654fcce17609b to your computer and use it in GitHub Desktop.
BracketBot Flashing Tool
#!/usr/bin/env bash
# Jetson Orin Nano setup script
# - Repairs NVIDIA local repo hash mismatches or disables broken file: repos
# - Installs CUDA keyring, cuDSS (best-effort), cuDNN 9.3.0.75-1 (best-effort)
# - Installs dev tools (git, git-lfs, ninja, venv, ffmpeg, etc.)
# - Adds user to hardware groups
# - Enables passwordless sudo
# - Clones BracketBot repos
# - Adds and runs ALSA setup script for ReSpeaker Lite
# - Ends with su -l $USER
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
# --- ensure root --------------------------------------------------------------
if [[ $EUID -ne 0 ]]; then
echo "[i] Re-running with sudo..."
exec sudo -E bash "$0" "$@"
fi
U=${SUDO_USER:-$(logname 2>/dev/null || echo "$USER")}
UH=$(eval echo ~"$U")
echo "[i] Starting setup for user: $U ($UH)"
# --- helpers ------------------------------------------------------------------
repair_local_repo_dir() {
local d="$1"
[[ -d "$d" ]] || return 0
if [[ -f "$d/Packages.gz" && ! -s "$d/Packages" ]]; then
echo "[i] Repair: creating $d/Packages from Packages.gz"
gunzip -c "$d/Packages.gz" > "$d/Packages" || true
fi
}
disable_local_file_repos() {
echo "[!] Disabling broken local NVIDIA repos..."
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*.list; do
[[ -f "$f" ]] || continue
sed -i -E 's|^(\s*deb\s+.*file:/var/(cudnn|l4t-cuda|nv-tensorrt)-local)|# \1|g' "$f"
done
}
apt_update_safe() {
set +e
apt-get clean
rm -rf /var/lib/apt/lists/*
apt-get update
local rc=$?
if [[ $rc -ne 0 ]]; then
echo "[!] apt-get update failed, repairing local NVIDIA repos..."
repair_local_repo_dir /var/cudnn-local-tegra-repo-ubuntu2204-9.3.0
repair_local_repo_dir /var/l4t-cuda-tegra-repo-ubuntu2204-12-6-local
repair_local_repo_dir /var/nv-tensorrt-local-tegra-repo-ubuntu2204-10.3.0-cuda-12.5
apt-get clean
rm -rf /var/lib/apt/lists/*
apt-get update
rc=$?
if [[ $rc -ne 0 ]]; then
disable_local_file_repos
apt-get clean
rm -rf /var/lib/apt/lists/*
apt-get update
rc=$?
fi
fi
set -e
return $rc
}
# --- system update ------------------------------------------------------------
echo "[i] Running apt repair/update..."
apt_update_safe
echo "[i] Installing developer packages..."
apt-get install -y --no-install-recommends \
ca-certificates wget curl gnupg gzip \
git git-lfs \
python3.10-venv python3-pip \
htop ncdu ffmpeg \
ninja-build || true
apt-get install -y ninja || true
# --- CUDA keyring -------------------------------------------------------------
if ! dpkg -s cuda-keyring >/dev/null 2>&1; then
echo "[i] Adding CUDA APT keyring..."
wget -qO /tmp/cuda-keyring_1.1-1_all.deb \
https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/arm64/cuda-keyring_1.1-1_all.deb
dpkg -i /tmp/cuda-keyring_1.1-1_all.deb
rm -f /tmp/cuda-keyring_1.1-1_all.deb
fi
apt_update_safe
echo "[i] Installing cuDSS (best effort)..."
apt-get install -y cudss || true
echo "[i] Installing cuDNN 9.3.0.75-1 (best effort)..."
apt-get install -y \
libcudnn9-cuda-12=9.3.0.75-1 \
libcudnn9-dev-cuda-12=9.3.0.75-1 \
libcudnn9-samples=9.3.0.75-1 || true
apt-mark hold libcudnn9-cuda-12 libcudnn9-dev-cuda-12 libcudnn9-samples || true
# --- Python setup -------------------------------------------------------------
echo "[i] Upgrading pip/build tools..."
python3 -m pip install --upgrade pip
python3 -m pip install --upgrade build setuptools
# --- Groups -------------------------------------------------------------------
echo "[i] Ensuring group memberships for ${U}..."
for g in sudo dialout video audio spi render i2c; do
getent group "$g" >/dev/null || groupadd "$g"
if ! id -nG "$U" | tr ' ' '\n' | grep -qx "$g"; then
usermod -aG "$g" "$U"
echo " - added $U to $g"
fi
done
# --- Passwordless sudo --------------------------------------------------------
SUDO_FILE="/etc/sudoers.d/99-${U}-nopasswd"
echo "[i] Enabling passwordless sudo for ${U}..."
echo "${U} ALL=(ALL) NOPASSWD:ALL" > "$SUDO_FILE"
chmod 440 "$SUDO_FILE"
# --- Clone/Update Repos -------------------------------------------------------
as_user() { sudo -u "$U" -H bash -lc "$*"; }
clone_or_update_repo() {
local url="$1"
local branch="${2:-}"
local name="${3:-$(basename "$url" .git)}"
as_user "mkdir -p '$UH'"
if [[ -d "$UH/$name/.git" ]]; then
echo "[i] Updating $name ..."
as_user "
set -e
cd '$UH/$name'
git fetch --all --prune
[[ -n '$branch' ]] && git checkout '$branch' || true
git pull --ff-only || true
git submodule update --init --recursive
"
else
echo "[i] Cloning $name ..."
if [[ -n "$branch" ]]; then
as_user "cd '$UH' && git clone --recursive -b '$branch' '$url' '$name'"
else
as_user "cd '$UH' && git clone --recursive '$url' '$name'"
fi
fi
chown -R "$U":"$U" "$UH/$name" || true
}
clone_or_update_repo "https://github.com/Bracket-Bot-Inc/BracketBotOS.git" "jetson" "BracketBotOS"
clone_or_update_repo "https://github.com/Bracket-Bot-Inc/BracketBotApps.git" "jetson" "BracketBotApps"
printf 'dashboard\nhey_bracketbot\n' > BracketBotApps/.autostart
printf 'OPENAI_API_KEY=' > BracketBotApps/.env
as_user "git lfs install --skip-repo || true"
# --- ALSA setup (adds your install_alsa.sh and runs it) -----------------------
echo "[i] Writing ALSA installer to $UH/install_alsa.sh ..."
cat > "$UH/install_alsa.sh" <<'EOS_ALSA'
#!/usr/bin/env bash
# Configure ALSA for ReSpeaker Lite on Jetson Orin Nano
# Makes ReSpeaker Lite (USB card 0) the default audio device
set -euo pipefail
# Re-run with sudo if not root
if [[ $EUID -ne 0 ]]; then
echo "[i] Re-running with sudo..."
exec sudo -E bash "$0" "$@"
fi
U=${SUDO_USER:-$(logname 2>/dev/null || echo "$USER")}
UH=$(eval echo ~"$U")
echo "[i] Configuring ALSA for ReSpeaker Lite..."
# Create user .asoundrc for ReSpeaker device alias
cat > "$UH/.asoundrc" <<'EOF'
# BracketBot ALSA Configuration
# Forces ReSpeaker Lite (USB card 0) as default device
pcm.!default {
type hw
card 0
device 0
}
ctl.!default {
type hw
card 0
}
# Named device alias for explicit access
pcm.respeaker {
type hw
card 0
device 0
}
ctl.respeaker {
type hw
card 0
}
EOF
chown "$U":"$U" "$UH/.asoundrc"
chmod 644 "$UH/.asoundrc"
echo " ✓ Created $UH/.asoundrc"
# Update system /etc/asound.conf to point to ReSpeaker (card 0) instead of APE
if [[ -f /etc/asound.conf ]]; then
cp /etc/asound.conf /etc/asound.conf.backup
sed -i 's|pcm "hw:APE,0"|pcm "hw:0,0"|g' /etc/asound.conf
echo " ✓ Updated /etc/asound.conf to use card 0 (ReSpeaker)"
echo " ✓ Backup saved to /etc/asound.conf.backup"
fi
echo
echo "[✓] ALSA configuration complete!"
echo " • Default device: ReSpeaker Lite (card 0)"
echo " • Named alias: 'respeaker' available"
echo " • User config: $UH/.asoundrc"
echo " • System config: /etc/asound.conf"
echo
echo "You may need to restart audio applications or run 'restart speakerphone'"
EOS_ALSA
chown "$U":"$U" "$UH/install_alsa.sh"
chmod +x "$UH/install_alsa.sh"
# Run it targeting the correct user (ensure SUDO_USER is set)
SUDO_USER="$U" bash "$UH/install_alsa.sh"
# --- Avahi (mDNS) configuration ----------------------------------------------
# Get hostname strictly from the `hostname` command
HN=$(hostname -s)
awk -v hn="$HN" 'BEGIN{sec=0;done=0} /^\[server\]/{sec=1} /^\[/{if($0!~/^\[server\]/)sec=0} sec && sub(/^[#[:space:]]*host-name[[:space:]]*=.*/,"host-name="hn){done=1} {print} END{if(!done){print ""; print "[server]"; print "host-name="hn}}' \
/etc/avahi/avahi-daemon.conf | sudo tee /etc/avahi/avahi-daemon.conf >/dev/null
systemctl restart avahi-daemon 2>/dev/null || true
# --- Final --------------------------------------------------------------------
echo
echo "[✓] Setup complete."
echo " • Passwordless sudo ENABLED for ${U}"
echo " • Repos cloned under: $UH/{BracketBotOS,BracketBotAI,BracketBotApps}"
echo " • ALSA configured for ReSpeaker Lite (card 0)"
echo " • Switching to a fresh login shell for ${U}..."
echo
exec su -l "$U"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment