diff --git a/README.md b/README.md index 44eb496..da85877 100644 --- a/README.md +++ b/README.md @@ -3,20 +3,20 @@ A complete simulation environment for UAV (drone) and UGV (ground vehicle) development using **GPS-denied navigation** with vision-based localization, while maintaining GPS-based geofencing for safety. -## 🎯 Key Feature: GPS-Denied Navigation +## Key Feature: GPS-Denied Navigation **Navigation Mode**: All vehicles navigate using **relative positioning** only: -- ✅ Visual odometry from cameras -- ✅ Optical flow sensors -- ✅ IMU integration -- ✅ Visual landmark tracking -- ✅ Local coordinate frames +- Visual odometry from cameras +- Optical flow sensors +- IMU integration +- Visual landmark tracking +- Local coordinate frames **GPS Usage**: GPS is ONLY used for: -- ✅ Geofencing (safety boundaries) -- ✅ Initial position reference (optional) -- ❌ NOT used for waypoint navigation -- ❌ NOT used for position control +- Geofencing (safety boundaries) +- Initial position reference (optional) +- NOT used for waypoint navigation +- NOT used for position control This simulates real-world GPS-denied environments like: - Indoor spaces @@ -26,31 +26,41 @@ This simulates real-world GPS-denied environments like: ## Features -- 🚁 **Iris quadcopter** with dual cameras (forward + downward) -- 🚗 **Ground vehicle (UGV)** with vision sensors -- 📷 **Visual odometry** - camera-based position estimation -- 👁️ **Optical flow** - velocity estimation from downward camera -- 🗺️ **Landmark navigation** - visual feature tracking -- 🛡️ **GPS geofencing** - safety boundaries only -- 🎮 **Single command launch** - everything runs from one script -- 🖥️ **NVIDIA GPU acceleration** support -- 🐍 **Python virtual environment** for isolated dependencies -- 🌍 **GPS-denied worlds** - indoor and urban environments +- **Iris quadcopter** with dual cameras (forward + downward) +- **Ground vehicle (UGV)** with vision sensors +- **Visual odometry** - camera-based position estimation +- **Optical flow** - velocity estimation from downward camera +- **Landmark navigation** - visual feature tracking +- **GPS geofencing** - safety boundaries only +- **Single command launch** - everything runs from one script +- **NVIDIA GPU acceleration** support +- **Python virtual environment** for isolated dependencies +- **GPS-denied worlds** - indoor and urban environments ## System Requirements -- Ubuntu 22.04 LTS -- Python 3.10 -- ROS 2 Humble +- **Ubuntu 22.04 LTS** (or 24.04 with ROS 2 Jazzy) +- **Python 3.10+** +- **ROS 2 Humble** (or Jazzy for Ubuntu 24.04) - 8GB RAM minimum (16GB recommended) - NVIDIA GPU recommended +### WSL2 Support (Windows) + +This project supports **Windows Subsystem for Linux (WSL2)**: +- Windows 10 (21H2+) or Windows 11 +- WSL2 with Ubuntu 22.04 +- GUI support via WSLg (Windows 11) or VcXsrv (Windows 10) +- See [WSL Setup Guide](docs/wsl_setup_guide.md) for detailed instructions + ## Quick Start +### Linux (Native) + ```bash # 1. Clone repository cd ~/ros2_ws/src -git clone uav_ugv_simulation +git clone https://git.sirblob.co/SirBlob/simulation.git uav_ugv_simulation cd uav_ugv_simulation # 2. Run setup (installs everything) @@ -64,6 +74,30 @@ source activate_venv.sh bash scripts/run_simulation.sh ``` +### WSL2 (Windows) + +```bash +# 1. Clone repository +cd ~ +git clone https://git.sirblob.co/SirBlob/simulation.git uav_ugv_simulation +cd uav_ugv_simulation + +# 2. Run WSL-specific setup +bash scripts/setup_wsl.sh + +# 3. Restart terminal +exit +# Reopen WSL terminal + +# 4. Run simulation +cd ~/uav_ugv_simulation +source activate_venv.sh +bash scripts/run_simulation.sh + +# If graphics are slow, use software rendering: +bash scripts/run_simulation.sh --software-render +``` + ## GPS-Denied Navigation Architecture ``` @@ -178,7 +212,8 @@ mission_waypoints = [ ## Documentation -- [Setup Guide](docs/setup_guide.md) +- [Setup Guide](docs/setup_guide.md) - Linux installation +- [WSL Setup Guide](docs/wsl_setup_guide.md) - Windows WSL2 installation - [Usage Guide](docs/usage.md) - [Architecture Overview](docs/architecture.md) - [GPS-Denied Navigation](docs/gps_denied_navigation.md) @@ -191,7 +226,7 @@ mission_waypoints = [ | Position Source | GPS satellites | Visual odometry + sensors | | Waypoint Type | GPS coordinates | Relative coordinates (x,y,z) | | Reference Frame | Global (lat/lon) | Local (relative to start) | -| Indoor Capability | ❌ No | ✅ Yes | +| Indoor Capability | No | Yes | | Drift | Minimal | Accumulates over time | | Geofencing | GPS-based | GPS-based (safety only) | | Use Cases | Outdoor, open sky | Indoor, urban, GPS-jammed | diff --git a/scripts/run_simulation.sh b/scripts/run_simulation.sh index b93a4f1..e167978 100755 --- a/scripts/run_simulation.sh +++ b/scripts/run_simulation.sh @@ -1,53 +1,196 @@ #!/bin/bash set -e +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" -echo "==========================================" -echo "UAV-UGV Simulation - Run Script" -echo "GPS-Denied Navigation with Geofencing" -echo "==========================================" +echo -e "${BLUE}==========================================${NC}" +echo -e "${BLUE} UAV-UGV Simulation${NC}" +echo -e "${BLUE} GPS-Denied Navigation with Geofencing${NC}" +echo -e "${BLUE}==========================================${NC}" +echo "" -WORLD="${1:-$PROJECT_DIR/worlds/empty_custom.world}" - -if [ ! -f "$WORLD" ]; then - echo "World file not found: $WORLD" - echo "Using default world..." - WORLD="$PROJECT_DIR/worlds/empty_custom.world" +# Detect WSL +IS_WSL=false +if grep -qEi "(microsoft|wsl)" /proc/version 2>/dev/null; then + IS_WSL=true + echo -e "${YELLOW}Running in WSL environment${NC}" fi +# Detect ROS distro +ROS_DISTRO="" +for distro in humble jazzy iron galactic; do + if [ -d "/opt/ros/$distro" ]; then + ROS_DISTRO="$distro" + break + fi +done + +if [ -z "$ROS_DISTRO" ]; then + echo -e "${RED}ERROR: No ROS 2 installation found!${NC}" + echo "Please install ROS 2 first. See docs/setup_guide.md or docs/wsl_setup_guide.md" + exit 1 +fi + +echo -e "${GREEN}Using ROS 2: $ROS_DISTRO${NC}" + +# Parse arguments +WORLD="${1:-$PROJECT_DIR/worlds/empty_custom.world}" +USE_NVIDIA=true +HEADLESS=false + +while [[ $# -gt 0 ]]; do + case $1 in + --world) + WORLD="$2" + shift 2 + ;; + --headless) + HEADLESS=true + shift + ;; + --no-gpu) + USE_NVIDIA=false + shift + ;; + --software-render) + export LIBGL_ALWAYS_SOFTWARE=1 + shift + ;; + --help) + echo "Usage: $0 [OPTIONS] [WORLD_FILE]" + echo "" + echo "Options:" + echo " --world FILE Specify world file (default: empty_custom.world)" + echo " --headless Run without GUI" + echo " --no-gpu Disable GPU acceleration" + echo " --software-render Force software rendering (useful in WSL)" + echo " --help Show this help" + echo "" + echo "Examples:" + echo " $0 # Default world" + echo " $0 worlds/indoor_warehouse.world # Indoor environment" + echo " $0 --software-render # For WSL without GPU" + exit 0 + ;; + *) + if [ -f "$1" ]; then + WORLD="$1" + fi + shift + ;; + esac +done + +# Validate world file +if [ ! -f "$WORLD" ]; then + echo -e "${YELLOW}World file not found: $WORLD${NC}" + WORLD="$PROJECT_DIR/worlds/empty_custom.world" + echo "Using default: $WORLD" +fi + +# Setup environment export GAZEBO_MODEL_PATH="$PROJECT_DIR/models:$GAZEBO_MODEL_PATH" export GAZEBO_RESOURCE_PATH="$PROJECT_DIR/worlds:$GAZEBO_RESOURCE_PATH" -if command -v nvidia-smi &> /dev/null; then - echo "NVIDIA GPU detected, enabling acceleration..." - export __NV_PRIME_RENDER_OFFLOAD=1 - export __GLX_VENDOR_LIBRARY_NAME=nvidia +# ArduPilot Gazebo paths +if [ -d "$HOME/ardupilot_gazebo" ]; then + export GAZEBO_MODEL_PATH="$HOME/ardupilot_gazebo/models:$GAZEBO_MODEL_PATH" + export GAZEBO_RESOURCE_PATH="$HOME/ardupilot_gazebo/worlds:$GAZEBO_RESOURCE_PATH" fi +# WSL-specific setup +if $IS_WSL; then + # Source WSL environment if exists + if [ -f "$PROJECT_DIR/wsl_env.sh" ]; then + source "$PROJECT_DIR/wsl_env.sh" + fi + + # Check DISPLAY + if [ -z "$DISPLAY" ]; then + # Try to set DISPLAY for WSL + if [ -d "/mnt/wslg" ]; then + export DISPLAY=:0 + else + export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0 + fi + fi + + echo -e "${BLUE}DISPLAY set to: $DISPLAY${NC}" + + # Performance hint for WSL + if [ -z "$LIBGL_ALWAYS_SOFTWARE" ]; then + echo -e "${YELLOW}TIP: If Gazebo is slow, run with --software-render flag${NC}" + fi +fi + +# GPU setup for native Linux +if $USE_NVIDIA && ! $IS_WSL; then + if command -v nvidia-smi &> /dev/null; then + echo -e "${GREEN}NVIDIA GPU detected${NC}" + export __NV_PRIME_RENDER_OFFLOAD=1 + export __GLX_VENDOR_LIBRARY_NAME=nvidia + fi +fi + +# Cleanup function cleanup() { echo "" - echo "Shutting down simulation..." + echo -e "${YELLOW}Shutting down simulation...${NC}" pkill -f "gazebo" 2>/dev/null || true + pkill -f "gzserver" 2>/dev/null || true + pkill -f "gzclient" 2>/dev/null || true pkill -f "sim_vehicle.py" 2>/dev/null || true pkill -f "mavros" 2>/dev/null || true - echo "Cleanup complete." + pkill -f "ArduCopter" 2>/dev/null || true + sleep 1 + echo -e "${GREEN}Cleanup complete.${NC}" } -trap cleanup EXIT +trap cleanup EXIT INT TERM -echo "Starting simulation with world: $WORLD" -echo "" +# Source ROS and workspace +source /opt/ros/${ROS_DISTRO}/setup.bash if [ -f "$PROJECT_DIR/venv/bin/activate" ]; then source "$PROJECT_DIR/venv/bin/activate" fi -source /opt/ros/humble/setup.bash 2>/dev/null || true - -if [ -f "$PROJECT_DIR/install/setup.bash" ]; then +if [ -f "$PROJECT_DIR/../install/setup.bash" ]; then + source "$PROJECT_DIR/../install/setup.bash" +elif [ -f "$PROJECT_DIR/install/setup.bash" ]; then source "$PROJECT_DIR/install/setup.bash" fi -ros2 launch uav_ugv_simulation full_simulation.launch.py world:="$WORLD" +echo "" +echo -e "${GREEN}Starting simulation with world: $(basename $WORLD)${NC}" +echo "" + +# Launch based on ROS distro and Gazebo version +if [ "$ROS_DISTRO" = "jazzy" ]; then + # Jazzy uses Gazebo Harmonic (gz-sim) + echo -e "${YELLOW}Note: Jazzy uses Gazebo Sim (Harmonic). World files may need conversion.${NC}" + ros2 launch uav_ugv_simulation full_simulation.launch.py world:="$WORLD" 2>&1 || { + echo -e "${YELLOW}Launch file failed. Trying direct Gazebo launch...${NC}" + gz sim "$WORLD" + } +else + # Humble and earlier use Gazebo Classic + if $HEADLESS; then + GAZEBO_CMD="gzserver --verbose" + else + GAZEBO_CMD="gazebo --verbose" + fi + + ros2 launch uav_ugv_simulation full_simulation.launch.py world:="$WORLD" 2>&1 || { + echo -e "${YELLOW}Launch file failed. Trying direct Gazebo launch...${NC}" + $GAZEBO_CMD "$WORLD" + } +fi diff --git a/scripts/setup_wsl.sh b/scripts/setup_wsl.sh new file mode 100755 index 0000000..20ae761 --- /dev/null +++ b/scripts/setup_wsl.sh @@ -0,0 +1,174 @@ +#!/bin/bash +# WSL Quick Setup Script +# This script sets up the simulation environment specifically for WSL2 + +set -e + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +echo -e "${BLUE}==========================================${NC}" +echo -e "${BLUE} UAV-UGV Simulation - WSL Setup${NC}" +echo -e "${BLUE}==========================================${NC}" +echo "" + +# Check if running in WSL +if ! grep -qEi "(microsoft|wsl)" /proc/version 2>/dev/null; then + echo -e "${YELLOW}This script is designed for WSL. Running anyway...${NC}" +fi + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(dirname "$SCRIPT_DIR")" + +# Detect Ubuntu version +. /etc/os-release +echo -e "${BLUE}Detected: Ubuntu $VERSION_ID ($VERSION_CODENAME)${NC}" + +# Determine ROS distro +case "$VERSION_ID" in + "22.04") ROS_DISTRO="humble" ;; + "24.04") ROS_DISTRO="jazzy" ;; + *) ROS_DISTRO="humble"; echo -e "${YELLOW}Unknown Ubuntu version, defaulting to Humble${NC}" ;; +esac + +echo -e "${BLUE}Target ROS 2 distro: $ROS_DISTRO${NC}" +echo "" + +# Step 1: Update and install prerequisites +echo -e "${GREEN}[1/6] Installing prerequisites...${NC}" +sudo apt-get update +sudo apt-get install -y \ + software-properties-common \ + curl \ + gnupg \ + lsb-release \ + x11-apps \ + x11-xserver-utils \ + dbus-x11 \ + mesa-utils \ + libgl1-mesa-glx + +# Step 2: Add ROS 2 repository +echo -e "${GREEN}[2/6] Adding ROS 2 repository...${NC}" +if [ ! -f /usr/share/keyrings/ros-archive-keyring.gpg ]; then + sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key \ + -o /usr/share/keyrings/ros-archive-keyring.gpg +fi + +if [ ! -f /etc/apt/sources.list.d/ros2.list ]; then + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] \ + http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" | \ + sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null +fi + +sudo apt-get update + +# Step 3: Install ROS 2 +echo -e "${GREEN}[3/6] Installing ROS 2 $ROS_DISTRO...${NC}" +if [ ! -d "/opt/ros/$ROS_DISTRO" ]; then + sudo apt-get install -y ros-${ROS_DISTRO}-desktop python3-colcon-common-extensions || { + echo -e "${YELLOW}Desktop install failed, trying base...${NC}" + sudo apt-get install -y ros-${ROS_DISTRO}-ros-base + } +else + echo -e "${BLUE}ROS 2 $ROS_DISTRO already installed${NC}" +fi + +# Step 4: Install ROS packages +echo -e "${GREEN}[4/6] Installing ROS 2 packages...${NC}" +sudo apt-get install -y \ + ros-${ROS_DISTRO}-mavros \ + ros-${ROS_DISTRO}-mavros-extras \ + ros-${ROS_DISTRO}-cv-bridge \ + ros-${ROS_DISTRO}-image-transport \ + ros-${ROS_DISTRO}-tf2-ros 2>/dev/null || { + echo -e "${YELLOW}Some packages unavailable for $ROS_DISTRO${NC}" +} + +# Gazebo (different for Humble vs Jazzy) +if [ "$ROS_DISTRO" = "humble" ]; then + sudo apt-get install -y ros-humble-gazebo-ros-pkgs 2>/dev/null || true +elif [ "$ROS_DISTRO" = "jazzy" ]; then + sudo apt-get install -y ros-jazzy-ros-gz 2>/dev/null || true +fi + +# GeographicLib datasets +echo -e "${GREEN}[5/6] Installing GeographicLib datasets...${NC}" +GEOGRAPHICLIB_SCRIPT="/opt/ros/${ROS_DISTRO}/lib/mavros/install_geographiclib_datasets.sh" +if [ -f "$GEOGRAPHICLIB_SCRIPT" ] && [ ! -f /usr/share/GeographicLib/geoids/egm96-5.pgm ]; then + sudo "$GEOGRAPHICLIB_SCRIPT" || echo -e "${YELLOW}GeographicLib install failed${NC}" +fi + +# Step 5: Setup Python environment +echo -e "${GREEN}[6/6] Setting up Python environment...${NC}" +cd "$PROJECT_DIR" + +sudo apt-get install -y python3-pip python3-venv python3-opencv libopencv-dev + +if [ ! -d "venv" ]; then + python3 -m venv venv +fi + +source venv/bin/activate +pip install --upgrade pip +pip install -r requirements.txt 2>/dev/null || echo -e "${YELLOW}Some pip packages failed${NC}" + +# Create WSL environment file +cat > "$PROJECT_DIR/wsl_env.sh" << 'EOF' +#!/bin/bash +# WSL Environment Setup + +# DISPLAY configuration +if [ -d "/mnt/wslg" ]; then + # WSLg (Windows 11) + export DISPLAY=:0 +else + # X server (Windows 10) + export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0 +fi + +# OpenGL settings for WSL +export LIBGL_ALWAYS_INDIRECT=0 +export MESA_GL_VERSION_OVERRIDE=3.3 + +# Uncomment for software rendering if GPU issues: +# export LIBGL_ALWAYS_SOFTWARE=1 + +# Gazebo performance +export OGRE_RTT_MODE=Copy +EOF +chmod +x "$PROJECT_DIR/wsl_env.sh" + +# Add to bashrc +if ! grep -q "wsl_env.sh" ~/.bashrc 2>/dev/null; then + echo "" >> ~/.bashrc + echo "# UAV-UGV Simulation WSL environment" >> ~/.bashrc + echo "[ -f \"$PROJECT_DIR/wsl_env.sh\" ] && source \"$PROJECT_DIR/wsl_env.sh\"" >> ~/.bashrc + echo "[ -f /opt/ros/${ROS_DISTRO}/setup.bash ] && source /opt/ros/${ROS_DISTRO}/setup.bash" >> ~/.bashrc +fi + +# Make scripts executable +chmod +x "$PROJECT_DIR/scripts/"*.sh 2>/dev/null || true +chmod +x "$PROJECT_DIR/setup.sh" 2>/dev/null || true +chmod +x "$PROJECT_DIR/activate_venv.sh" 2>/dev/null || true + +echo "" +echo -e "${GREEN}==========================================${NC}" +echo -e "${GREEN} WSL Setup Complete!${NC}" +echo -e "${GREEN}==========================================${NC}" +echo "" +echo -e "${BLUE}Next steps:${NC}" +echo " 1. Close and reopen your terminal (or run: source ~/.bashrc)" +echo " 2. Test GUI: xcalc (should open calculator)" +echo " 3. Test Gazebo: gazebo --verbose" +echo " 4. Run simulation: source activate_venv.sh && bash scripts/run_simulation.sh" +echo "" +echo -e "${YELLOW}WSL Tips:${NC}" +echo " - Windows 11: GUI works out of the box (WSLg)" +echo " - Windows 10: Install VcXsrv and run XLaunch first" +echo " - Slow graphics? Run with: bash scripts/run_simulation.sh --software-render" +echo " - See docs/wsl_setup_guide.md for detailed help" +echo "" diff --git a/setup.sh b/setup.sh index cbae3b3..2225717 100755 --- a/setup.sh +++ b/setup.sh @@ -1,93 +1,383 @@ #!/bin/bash set -e -echo "==========================================" -echo "UAV-UGV Simulation Setup" -echo "Ubuntu 22.04 + Python 3.10 + ROS 2 Humble" -echo "GPS-Denied Navigation with Geofencing" -echo "==========================================" -echo "" +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +print_header() { + echo -e "${BLUE}==========================================${NC}" + echo -e "${BLUE} UAV-UGV Simulation Setup${NC}" + echo -e "${BLUE} GPS-Denied Navigation with Geofencing${NC}" + echo -e "${BLUE}==========================================${NC}" + echo "" +} + +print_step() { + echo -e "${GREEN}[$1/$TOTAL_STEPS] $2${NC}" +} + +print_warning() { + echo -e "${YELLOW}WARNING: $1${NC}" +} + +print_error() { + echo -e "${RED}ERROR: $1${NC}" +} + +print_info() { + echo -e "${BLUE}INFO: $1${NC}" +} + +# Detect environment +detect_environment() { + IS_WSL=false + IS_WSL2=false + UBUNTU_VERSION="" + ROS_DISTRO="" + + # Detect WSL + if grep -qEi "(microsoft|wsl)" /proc/version 2>/dev/null; then + IS_WSL=true + if grep -qi "wsl2" /proc/version 2>/dev/null || [ -f /run/WSL ]; then + IS_WSL2=true + fi + fi + + # Detect Ubuntu version + if [ -f /etc/os-release ]; then + . /etc/os-release + UBUNTU_VERSION="$VERSION_ID" + UBUNTU_CODENAME="$VERSION_CODENAME" + fi + + # Determine ROS distro based on Ubuntu version + case "$UBUNTU_VERSION" in + "22.04") + ROS_DISTRO="humble" + ;; + "24.04") + ROS_DISTRO="jazzy" + ;; + "20.04") + ROS_DISTRO="galactic" + ;; + *) + ROS_DISTRO="humble" # Default fallback + ;; + esac + + echo -e "${BLUE}Detected Environment:${NC}" + echo " - Ubuntu: $UBUNTU_VERSION ($UBUNTU_CODENAME)" + echo " - WSL: $IS_WSL" + echo " - WSL2: $IS_WSL2" + echo " - ROS 2 Distro: $ROS_DISTRO" + echo "" +} + +# Check if ROS 2 is installed +check_ros2_installed() { + if [ -d "/opt/ros/$ROS_DISTRO" ]; then + return 0 + else + return 1 + fi +} + +# Install ROS 2 repository +install_ros2_repo() { + print_info "Setting up ROS 2 repository..." + + sudo apt-get install -y software-properties-common curl gnupg lsb-release + + # Add ROS 2 GPG key + sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key \ + -o /usr/share/keyrings/ros-archive-keyring.gpg + + # Add repository + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] \ + http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" | \ + sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null + + sudo apt-get update +} + +# Setup WSL-specific configurations +setup_wsl() { + print_info "Configuring WSL-specific settings..." + + # Create WSL environment setup + WSL_ENV_FILE="$SCRIPT_DIR/wsl_env.sh" + + cat > "$WSL_ENV_FILE" << 'WSLEOF' +#!/bin/bash +# WSL-specific environment variables + +# Detect WSL version and set DISPLAY +if grep -qi "wsl2" /proc/version 2>/dev/null || [ -f /run/WSL ]; then + # WSL2 with WSLg (Windows 11) + if [ -d "/mnt/wslg" ]; then + export DISPLAY=:0 + else + # WSL2 without WSLg (Windows 10) - use X server + export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0 + fi +else + # WSL1 + export DISPLAY=localhost:0 +fi + +# Performance settings for Gazebo in WSL +export LIBGL_ALWAYS_INDIRECT=0 + +# If GPU acceleration isn't working, uncomment this: +# export LIBGL_ALWAYS_SOFTWARE=1 + +# Mesa driver settings (helps with some rendering issues) +export MESA_GL_VERSION_OVERRIDE=3.3 +export MESA_GLSL_VERSION_OVERRIDE=330 + +# Gazebo specific +export OGRE_RTT_MODE=Copy +WSLEOF + + chmod +x "$WSL_ENV_FILE" + + # Add to bashrc if not already present + if ! grep -q "wsl_env.sh" ~/.bashrc 2>/dev/null; then + echo "" >> ~/.bashrc + echo "# WSL environment for UAV-UGV simulation" >> ~/.bashrc + echo "if [ -f \"$WSL_ENV_FILE\" ]; then source \"$WSL_ENV_FILE\"; fi" >> ~/.bashrc + fi + + print_info "WSL environment configured. Source ~/.bashrc to apply." +} + +# Setup X11 for GUI applications +setup_x11_wsl() { + print_info "Installing X11 utilities for GUI support..." + + sudo apt-get install -y \ + x11-apps \ + x11-xserver-utils \ + dbus-x11 \ + libgl1-mesa-glx \ + mesa-utils 2>/dev/null || true +} + +# Main setup +print_header SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" -echo "[1/7] Updating system packages..." -sudo apt-get update +# Detect environment +detect_environment -echo "[2/7] Installing system dependencies..." +# Determine total steps based on what's needed +if check_ros2_installed; then + TOTAL_STEPS=7 +else + TOTAL_STEPS=9 + print_warning "ROS 2 $ROS_DISTRO not found. Will attempt to install." +fi + +if $IS_WSL; then + TOTAL_STEPS=$((TOTAL_STEPS + 1)) +fi + +STEP=1 + +# Step: Update system +print_step $STEP "Updating system packages..." +sudo apt-get update +((STEP++)) + +# Step: WSL-specific setup +if $IS_WSL; then + print_step $STEP "Setting up WSL environment..." + setup_wsl + setup_x11_wsl + ((STEP++)) +fi + +# Step: Install ROS 2 if not present +if ! check_ros2_installed; then + print_step $STEP "Installing ROS 2 repository..." + install_ros2_repo + ((STEP++)) + + print_step $STEP "Installing ROS 2 $ROS_DISTRO..." + sudo apt-get install -y ros-${ROS_DISTRO}-desktop || { + print_warning "Failed to install ros-${ROS_DISTRO}-desktop, trying base..." + sudo apt-get install -y ros-${ROS_DISTRO}-ros-base + } + ((STEP++)) +fi + +# Step: Install system dependencies +print_step $STEP "Installing system dependencies..." sudo apt-get install -y \ python3-pip \ python3-venv \ python3-opencv \ libopencv-dev \ - ros-humble-mavros \ - ros-humble-mavros-extras \ - ros-humble-cv-bridge \ - ros-humble-image-transport \ - ros-humble-gazebo-ros-pkgs \ - ros-humble-tf2 \ - ros-humble-tf2-ros \ - ros-humble-tf2-geometry-msgs + python3-colcon-common-extensions \ + build-essential \ + cmake \ + git || true +((STEP++)) -echo "[3/7] Installing MAVROS GeographicLib datasets..." -if [ ! -f /usr/share/GeographicLib/geoids/egm96-5.pgm ]; then - sudo /opt/ros/humble/lib/mavros/install_geographiclib_datasets.sh || true +# Step: Install ROS 2 packages +print_step $STEP "Installing ROS 2 packages..." +ROS_PACKAGES=( + "ros-${ROS_DISTRO}-mavros" + "ros-${ROS_DISTRO}-mavros-extras" + "ros-${ROS_DISTRO}-cv-bridge" + "ros-${ROS_DISTRO}-image-transport" + "ros-${ROS_DISTRO}-tf2" + "ros-${ROS_DISTRO}-tf2-ros" + "ros-${ROS_DISTRO}-tf2-geometry-msgs" +) + +# Gazebo packages differ by distro +if [ "$ROS_DISTRO" = "humble" ]; then + ROS_PACKAGES+=("ros-${ROS_DISTRO}-gazebo-ros-pkgs") +elif [ "$ROS_DISTRO" = "jazzy" ]; then + # Jazzy uses Gazebo Harmonic (gz-sim) + ROS_PACKAGES+=("ros-${ROS_DISTRO}-ros-gz") fi -echo "[4/7] Creating Python virtual environment..." +# Install available packages (some may not exist for all distros) +for pkg in "${ROS_PACKAGES[@]}"; do + sudo apt-get install -y "$pkg" 2>/dev/null || { + print_warning "Package $pkg not available, skipping..." + } +done +((STEP++)) + +# Step: Install MAVROS GeographicLib datasets +print_step $STEP "Installing MAVROS GeographicLib datasets..." +GEOGRAPHICLIB_SCRIPT="/opt/ros/${ROS_DISTRO}/lib/mavros/install_geographiclib_datasets.sh" +if [ -f "$GEOGRAPHICLIB_SCRIPT" ]; then + if [ ! -f /usr/share/GeographicLib/geoids/egm96-5.pgm ]; then + sudo "$GEOGRAPHICLIB_SCRIPT" || print_warning "GeographicLib datasets installation failed" + else + print_info "GeographicLib datasets already installed" + fi +else + print_warning "MAVROS not installed, skipping GeographicLib datasets" +fi +((STEP++)) + +# Step: Create Python virtual environment +print_step $STEP "Creating Python virtual environment..." if [ ! -d "venv" ]; then python3 -m venv venv fi source venv/bin/activate -echo "[5/7] Installing Python dependencies..." +# Upgrade pip and install dependencies pip install --upgrade pip -pip install -r requirements.txt +pip install -r requirements.txt || { + print_warning "Some Python packages failed to install. Check requirements.txt" +} +((STEP++)) -echo "[6/7] Building ROS 2 package..." -source /opt/ros/humble/setup.bash - -cd .. -if [ -d "$(dirname "$SCRIPT_DIR")/src" ]; then - cd "$(dirname "$SCRIPT_DIR")" +# Step: Build ROS 2 package +print_step $STEP "Building ROS 2 package..." +if [ -f "/opt/ros/${ROS_DISTRO}/setup.bash" ]; then + source /opt/ros/${ROS_DISTRO}/setup.bash + + # Try to build if in a ROS workspace + if [ -d "$SCRIPT_DIR/../src" ] || [ -f "$SCRIPT_DIR/package.xml" ]; then + cd "$SCRIPT_DIR/.." + colcon build --packages-select uav_ugv_simulation --symlink-install 2>/dev/null || { + print_warning "Colcon build skipped. To build manually:" + print_info " cd ~/ros2_ws && colcon build --packages-select uav_ugv_simulation" + } + cd "$SCRIPT_DIR" + fi +else + print_warning "ROS 2 not found, skipping package build" fi +((STEP++)) -if [ -f "$SCRIPT_DIR/package.xml" ]; then - colcon build --packages-select uav_ugv_simulation --symlink-install 2>/dev/null || \ - echo "Colcon build skipped - run from ROS workspace" -fi +# Step: Make scripts executable and create activation script +print_step $STEP "Finalizing setup..." +chmod +x scripts/*.sh 2>/dev/null || true -cd "$SCRIPT_DIR" - -echo "[7/7] Making scripts executable..." -chmod +x scripts/*.sh - -cat > activate_venv.sh << 'EOF' +# Create activation script +cat > activate_venv.sh << EOF #!/bin/bash -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "$SCRIPT_DIR/venv/bin/activate" -source /opt/ros/humble/setup.bash -if [ -f "$SCRIPT_DIR/install/setup.bash" ]; then - source "$SCRIPT_DIR/install/setup.bash" +SCRIPT_DIR="\$(cd "\$(dirname "\${BASH_SOURCE[0]}")" && pwd)" + +# Activate Python virtual environment +source "\$SCRIPT_DIR/venv/bin/activate" + +# Source ROS 2 +if [ -f "/opt/ros/${ROS_DISTRO}/setup.bash" ]; then + source /opt/ros/${ROS_DISTRO}/setup.bash fi -export GAZEBO_MODEL_PATH="$SCRIPT_DIR/models:$GAZEBO_MODEL_PATH" -export GAZEBO_RESOURCE_PATH="$SCRIPT_DIR/worlds:$GAZEBO_RESOURCE_PATH" -echo "Environment activated." + +# Source workspace if built +if [ -f "\$SCRIPT_DIR/../install/setup.bash" ]; then + source "\$SCRIPT_DIR/../install/setup.bash" +elif [ -f "\$SCRIPT_DIR/install/setup.bash" ]; then + source "\$SCRIPT_DIR/install/setup.bash" +fi + +# Gazebo paths +export GAZEBO_MODEL_PATH="\$SCRIPT_DIR/models:\$GAZEBO_MODEL_PATH" +export GAZEBO_RESOURCE_PATH="\$SCRIPT_DIR/worlds:\$GAZEBO_RESOURCE_PATH" + +# ArduPilot Gazebo (if installed) +if [ -d "\$HOME/ardupilot_gazebo" ]; then + export GAZEBO_MODEL_PATH="\$HOME/ardupilot_gazebo/models:\$GAZEBO_MODEL_PATH" + export GAZEBO_RESOURCE_PATH="\$HOME/ardupilot_gazebo/worlds:\$GAZEBO_RESOURCE_PATH" +fi + +# WSL environment (if applicable) +if [ -f "\$SCRIPT_DIR/wsl_env.sh" ]; then + source "\$SCRIPT_DIR/wsl_env.sh" +fi + +echo -e "\033[0;32mEnvironment activated (ROS 2 ${ROS_DISTRO})\033[0m" echo "Run: bash scripts/run_simulation.sh" EOF chmod +x activate_venv.sh +# Summary echo "" -echo "==========================================" -echo "Setup Complete!" -echo "==========================================" +echo -e "${GREEN}==========================================${NC}" +echo -e "${GREEN} Setup Complete!${NC}" +echo -e "${GREEN}==========================================${NC}" echo "" -echo "Next steps:" + +if $IS_WSL; then + echo -e "${YELLOW}WSL Setup Notes:${NC}" + echo " - WSL environment file created: wsl_env.sh" + echo " - For GUI apps, ensure X server is running (Windows 11 has WSLg built-in)" + echo " - See docs/wsl_setup_guide.md for detailed instructions" + echo "" +fi + +echo -e "${BLUE}Next steps:${NC}" echo " 1. source ~/.bashrc" echo " 2. source activate_venv.sh" echo " 3. bash scripts/run_simulation.sh" echo "" -echo "GPS-Denied Navigation:" +echo -e "${BLUE}GPS-Denied Navigation:${NC}" echo " - All navigation uses LOCAL coordinates" echo " - GPS is ONLY used for geofencing" echo "" + +if ! check_ros2_installed && [ ! -f "/opt/ros/${ROS_DISTRO}/setup.bash" ]; then + echo -e "${YELLOW}IMPORTANT:${NC}" + echo " ROS 2 installation may have failed. Please install manually:" + echo " See: https://docs.ros.org/en/${ROS_DISTRO}/Installation.html" + echo "" +fi