| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # β ROS Dashboard β One-Shot Startup Script β | |
| # β Run this file and the entire project starts automatically. β | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| set -euo pipefail | |
| # ββ Colors βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| GREEN='\033[0;32m' | |
| CYAN='\033[0;36m' | |
| YELLOW='\033[1;33m' | |
| RED='\033[0;31m' | |
| BOLD='\033[1m' | |
| RESET='\033[0m' | |
| # ββ Helpers βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| info() { echo -e "${CYAN}[INFO]${RESET} $*"; } | |
| success() { echo -e "${GREEN}[OK]${RESET} $*"; } | |
| warn() { echo -e "${YELLOW}[WARN]${RESET} $*"; } | |
| error() { echo -e "${RED}[ERROR]${RESET} $*"; } | |
| section() { echo -e "\n${BOLD}${CYAN}βββ $* βββ${RESET}"; } | |
| # ββ Change to the script's own directory so paths are always correct | |
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | |
| cd "$SCRIPT_DIR" | |
| # ββ Banner βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| echo "" | |
| echo -e "${BOLD}${GREEN}" | |
| echo " βββββββ βββββββ ββββββββ βββββββ ββββββ βββββββββββ βββ" | |
| echo " βββββββββββββββββββββββββ βββββββββββββββββββββββββββ βββ" | |
| echo " βββββββββββ βββββββββββ βββ βββββββββββββββββββββββββββ" | |
| echo " βββββββββββ βββββββββββ βββ βββββββββββββββββββββββββββ" | |
| echo " βββ ββββββββββββββββββββ βββββββββββ ββββββββββββββ βββ" | |
| echo " βββ βββ βββββββ ββββββββ βββββββ βββ ββββββββββββββ βββ" | |
| echo -e "${RESET}" | |
| echo -e " ${BOLD}ROS 2 Simulation Dashboard β Startup${RESET}" | |
| echo "" | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 1. DEPENDENCY CHECKS | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| section "Checking Dependencies" | |
| check_cmd() { | |
| if command -v "$1" &>/dev/null; then | |
| success "$1 found" | |
| else | |
| warn "$1 not found β $2" | |
| fi | |
| } | |
| check_cmd node "Install Node.js: https://nodejs.org" | |
| check_cmd npm "Install npm alongside Node.js" | |
| check_cmd Xvfb "Install with: sudo apt install xvfb" | |
| check_cmd x11vnc "Install with: sudo apt install x11vnc" | |
| check_cmd websockify "Install with: sudo apt install websockify" | |
| # Node.js is required β fail fast if missing | |
| if ! command -v node &>/dev/null; then | |
| error "Node.js is required but not found. Please install it first." | |
| exit 1 | |
| fi | |
| # ββ Install npm dependencies if needed βββββββββββββββββββββββββββββ | |
| if [ ! -d "node_modules" ]; then | |
| section "Installing npm Dependencies" | |
| npm install | |
| success "npm install complete" | |
| else | |
| info "node_modules already present β skipping npm install" | |
| fi | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 2. CLEANUP STALE PROCESSES | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| section "Cleaning Up Stale Processes" | |
| kill_quietly() { pkill -f "$1" 2>/dev/null || true; } | |
| kill_quietly "Xvfb :20" | |
| kill_quietly "x11vnc.*5920" | |
| kill_quietly "websockify.*6080" | |
| kill_quietly "node server.js" | |
| kill_quietly "ros2 run" | |
| kill_quietly "ros2 launch" | |
| kill_quietly "rviz2" | |
| sleep 1 | |
| success "Cleanup done" | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 3. DETERMINE PORT | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| PORT="${PORT:-3000}" | |
| DASHBOARD_URL="http://localhost:${PORT}" | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # 4. START THE SERVER | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| section "Starting ROS Dashboard Server" | |
| info "Server will be available at ${BOLD}${DASHBOARD_URL}${RESET}" | |
| info "Press Ctrl+C to stop everything" | |
| echo "" | |
| # ββ Trap Ctrl+C for a clean shutdown ββββββββββββββββββββββββββββββ | |
| cleanup() { | |
| echo "" | |
| section "Shutting Down" | |
| kill_quietly "node server.js" | |
| kill_quietly "Xvfb :20" | |
| kill_quietly "x11vnc.*5920" | |
| kill_quietly "websockify.*6080" | |
| kill_quietly "ros2 run" | |
| kill_quietly "ros2 launch" | |
| kill_quietly "rviz2" | |
| success "All processes stopped. Goodbye!" | |
| exit 0 | |
| } | |
| trap cleanup SIGINT SIGTERM | |
| # ββ Auto-open browser after a short delay (best-effort) βββββββββββ | |
| ( | |
| sleep 3 | |
| if command -v xdg-open &>/dev/null; then | |
| xdg-open "$DASHBOARD_URL" &>/dev/null & | |
| elif command -v sensible-browser &>/dev/null; then | |
| sensible-browser "$DASHBOARD_URL" &>/dev/null & | |
| fi | |
| ) & | |
| # ββ Launch server (foreground so logs stream to terminal) βββββββββ | |
| PORT="${PORT}" node server.js | |