- Dockerfile: L4T R32.6.1 (JetPack 4.6) base + ROS2 Humble + SLAM stack (slam_toolbox, Nav2, rplidar_ros, realsense2_camera, robot_localization) - docker-compose.yml: multi-service stack (ROS2, RPLIDAR A1M8, D435i, STM32 bridge) with device passthrough, host networking for DDS, persistent map volume - docs/pinout.md: full GPIO/I2C/UART pinout for STM32F722 bridge (USB CDC + UART fallback), RealSense D435i (USB3), RPLIDAR A1M8, udev rules - docs/power-budget.md: 10W envelope analysis with per-component breakdown, mitigation strategies (RPLIDAR gating, D435i 640p, nvpmodel modes) - scripts/setup-jetson.sh: host one-shot setup (Docker, nvidia-container-runtime, udev rules, MAXN power mode, swap) - scripts/build-and-run.sh: build/up/down/shell/slam/status helper Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
128 lines
5.2 KiB
Bash
128 lines
5.2 KiB
Bash
#!/usr/bin/env bash
|
|
# Jetson Nano host setup script
|
|
# Run once on fresh JetPack 4.6 installation
|
|
# Usage: sudo bash setup-jetson.sh
|
|
|
|
set -euo pipefail
|
|
|
|
echo "=== Jetson Nano Host Setup — saltybot ==="
|
|
echo "JetPack 4.6 / L4T R32.6.1 expected"
|
|
|
|
# ── Verify we're on Jetson ────────────────────────────────────────────────────
|
|
if ! uname -m | grep -q aarch64; then
|
|
echo "ERROR: Must run on Jetson (aarch64). Got: $(uname -m)"
|
|
exit 1
|
|
fi
|
|
|
|
# ── System update ─────────────────────────────────────────────────────────────
|
|
apt-get update && apt-get upgrade -y
|
|
|
|
# ── Install Docker + NVIDIA runtime ──────────────────────────────────────────
|
|
if ! command -v docker &>/dev/null; then
|
|
echo "[+] Installing Docker..."
|
|
curl -fsSL https://get.docker.com | sh
|
|
usermod -aG docker "$SUDO_USER"
|
|
fi
|
|
|
|
# NVIDIA container runtime
|
|
if ! dpkg -l | grep -q nvidia-container-runtime; then
|
|
echo "[+] Installing NVIDIA Container Runtime..."
|
|
distribution=$(. /etc/os-release; echo $ID$VERSION_ID)
|
|
curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | apt-key add -
|
|
curl -s -L "https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list" \
|
|
> /etc/apt/sources.list.d/nvidia-container-runtime.list
|
|
apt-get update
|
|
apt-get install -y nvidia-container-runtime
|
|
fi
|
|
|
|
# Configure Docker daemon for NVIDIA runtime
|
|
cat > /etc/docker/daemon.json << 'EOF'
|
|
{
|
|
"runtimes": {
|
|
"nvidia": {
|
|
"path": "nvidia-container-runtime",
|
|
"runtimeArgs": []
|
|
}
|
|
},
|
|
"default-runtime": "nvidia"
|
|
}
|
|
EOF
|
|
systemctl restart docker
|
|
|
|
# ── Set Jetson power mode to MAXN 10W ────────────────────────────────────────
|
|
echo "[+] Setting MAXN 10W power mode..."
|
|
nvpmodel -m 0
|
|
jetson_clocks
|
|
|
|
# ── Install udev rules ────────────────────────────────────────────────────────
|
|
echo "[+] Installing udev rules..."
|
|
cat > /etc/udev/rules.d/99-saltybot.rules << 'EOF'
|
|
# RPLIDAR A1M8 (SiliconLabs CP2102)
|
|
KERNEL=="ttyUSB*", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", \
|
|
SYMLINK+="rplidar", MODE="0666"
|
|
|
|
# STM32 USB CDC (STMicroelectronics Virtual COM)
|
|
KERNEL=="ttyACM*", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", \
|
|
SYMLINK+="stm32-bridge", MODE="0666"
|
|
|
|
# Intel RealSense D435i
|
|
SUBSYSTEM=="usb", ATTRS{idVendor}=="8086", ATTRS{idProduct}=="0b3a", \
|
|
MODE="0666"
|
|
EOF
|
|
|
|
udevadm control --reload-rules
|
|
udevadm trigger
|
|
|
|
# ── Install RealSense udev rules ──────────────────────────────────────────────
|
|
echo "[+] Installing RealSense udev rules..."
|
|
if [ -f /etc/udev/rules.d/99-realsense-libusb.rules ]; then
|
|
echo " Already installed."
|
|
else
|
|
# Download from librealsense repo
|
|
wget -q -O /etc/udev/rules.d/99-realsense-libusb.rules \
|
|
https://raw.githubusercontent.com/IntelRealSense/librealsense/master/config/99-realsense-libusb.rules
|
|
udevadm control --reload-rules
|
|
udevadm trigger
|
|
fi
|
|
|
|
# ── Enable I2C + UART ─────────────────────────────────────────────────────────
|
|
echo "[+] Enabling I2C and UART..."
|
|
modprobe i2c-dev
|
|
# Add user to i2c and dialout groups
|
|
usermod -aG i2c,dialout,gpio "$SUDO_USER"
|
|
|
|
# ── Configure UART (disable console on ttyTHS1) ───────────────────────────────
|
|
# ttyTHS1 is the 40-pin header UART — disable serial console to free it
|
|
if grep -q "console=ttyS0" /boot/extlinux/extlinux.conf; then
|
|
echo "[+] UART ttyTHS1 already free for application use."
|
|
else
|
|
echo "[!] Warning: Check /boot/extlinux/extlinux.conf if serial console"
|
|
echo " is using ttyTHS1. Disable it to use UART for STM32 bridge."
|
|
fi
|
|
|
|
# ── Docker Compose ────────────────────────────────────────────────────────────
|
|
if ! command -v docker-compose &>/dev/null && ! docker compose version &>/dev/null 2>&1; then
|
|
echo "[+] Installing docker-compose..."
|
|
pip3 install docker-compose
|
|
fi
|
|
|
|
# ── Swap (improve stability under memory pressure) ────────────────────────────
|
|
if [ "$(swapon --show | wc -l)" -le 1 ]; then
|
|
echo "[+] Creating 4GB swap file..."
|
|
fallocate -l 4G /swapfile
|
|
chmod 600 /swapfile
|
|
mkswap /swapfile
|
|
swapon /swapfile
|
|
echo '/swapfile none swap sw 0 0' >> /etc/fstab
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== Setup complete ==="
|
|
echo "Please log out and back in for group membership to take effect."
|
|
echo ""
|
|
echo "Next steps:"
|
|
echo " 1. cd jetson/"
|
|
echo " 2. docker compose build"
|
|
echo " 3. docker compose up -d"
|
|
echo " 4. docker compose logs -f"
|