Update Install Scripts

This commit is contained in:
2026-02-09 04:20:22 +00:00
parent e70d4a8fcd
commit 5c0d3e2fb4
10 changed files with 1072 additions and 836 deletions

300
README.md
View File

@@ -1,7 +1,7 @@
# UAV-UGV Gazebo SITL Simulation # UAV-UGV Gazebo SITL Simulation
## GPS-Denied Navigation with Geofencing ## GPS-Denied Navigation with Geofencing
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. A production-ready 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
@@ -14,15 +14,78 @@ A complete simulation environment for UAV (drone) and UGV (ground vehicle) devel
**GPS Usage**: GPS is ONLY used for: **GPS Usage**: GPS is ONLY used for:
- Geofencing (safety boundaries) - Geofencing (safety boundaries)
- Initial position reference (optional)
- NOT used for waypoint navigation - NOT used for waypoint navigation
- NOT used for position control - NOT used for position control
This simulates real-world GPS-denied environments like: ## System Requirements
- Indoor spaces
- Urban canyons - **Ubuntu 22.04 LTS** (or 24.04)
- GPS-jammed areas - **16GB RAM** recommended (8GB minimum)
- Under bridges/tunnels - **50GB disk space** (for ArduPilot + Gazebo)
- NVIDIA GPU recommended but not required
### Supported Platforms
- Native Ubuntu Linux
- Windows WSL2 with Ubuntu 22.04
## Installation (One Command)
```bash
# Clone the repository
git clone https://git.sirblob.co/SirBlob/simulation.git
cd simulation
# Run the complete setup (installs everything)
bash setup.sh
```
The setup script installs:
- ROS 2 Humble
- Gazebo 11
- ArduPilot SITL
- ardupilot_gazebo plugin
- MAVROS
- Python dependencies
**Note**: Full installation takes 20-40 minutes depending on your internet speed.
## Quick Start
```bash
# Navigate to project
cd ~/simulation # or wherever you cloned it
# Activate environment (sets up ROS 2, Gazebo, ArduPilot, Python)
source activate_venv.sh
# Run simulation
bash scripts/run_simulation.sh
# For WSL (if graphics issues):
bash scripts/run_simulation.sh --software-render
```
## Controlling the UAV
Once the simulation is running, control via ROS 2:
```bash
# Arm the drone
ros2 service call /mavros/cmd/arming mavros_msgs/srv/CommandBool "{value: true}"
# Set GUIDED mode (allows position control)
ros2 service call /mavros/set_mode mavros_msgs/srv/SetMode "{custom_mode: 'GUIDED'}"
# Takeoff to 5 meters
ros2 service call /mavros/cmd/takeoff mavros_msgs/srv/CommandTOL "{altitude: 5}"
# Fly to position (LOCAL coordinates - no GPS!)
ros2 topic pub /mavros/setpoint_position/local geometry_msgs/PoseStamped \
"{header: {frame_id: 'map'}, pose: {position: {x: 10, y: 5, z: 5}}}"
# Land
ros2 service call /mavros/cmd/land mavros_msgs/srv/CommandTOL "{}"
```
## Features ## Features
@@ -30,73 +93,10 @@ This simulates real-world GPS-denied environments like:
- **Ground vehicle (UGV)** with vision sensors - **Ground vehicle (UGV)** with vision sensors
- **Visual odometry** - camera-based position estimation - **Visual odometry** - camera-based position estimation
- **Optical flow** - velocity estimation from downward camera - **Optical flow** - velocity estimation from downward camera
- **Landmark navigation** - visual feature tracking
- **GPS geofencing** - safety boundaries only - **GPS geofencing** - safety boundaries only
- **Single command launch** - everything runs from one script - **ArduPilot SITL** - real flight controller firmware
- **NVIDIA GPU acceleration** support - **MAVROS** - ROS 2 interface for MAVLink
- **Python virtual environment** for isolated dependencies - **Multiple worlds** - indoor warehouse, urban canyon
- **GPS-denied worlds** - indoor and urban environments
## System Requirements
- **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 https://git.sirblob.co/SirBlob/simulation.git uav_ugv_simulation
cd uav_ugv_simulation
# 2. Run setup (installs everything)
bash setup.sh
# 3. Restart terminal or reload bash
source ~/.bashrc
# 4. Activate virtual environment and run
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 ## GPS-Denied Navigation Architecture
@@ -121,103 +121,57 @@ bash scripts/run_simulation.sh --software-render
┌─────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────┐
Navigation Controller ArduPilot Flight Controller │
Commands: "Move 5m forward, 3m right" Receives position via MAVROS (external nav)
(Relative coordinates only, NO GPS waypoints) Controls motors based on local setpoints
└─────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────┘
SEPARATE SAFETY LAYER (GPS-based):
┌─────────────────────────────────────────────────────┐
│ Geofence Monitor │
│ GPS position → Check against boundaries │
│ If outside: Emergency RTL or hold │
└─────────────────────────────────────────────────────┘
```
## Navigation Modes
### 1. **Vision-Only Mode** (Default)
- Uses camera for all position estimates
- Suitable for structured environments
- Requires good lighting and visual features
### 2. **Optical Flow Mode**
- Uses downward camera for velocity
- Works well at low altitudes
- Good for hovering and slow flight
### 3. **Hybrid Mode**
- Combines visual odometry + optical flow + IMU
- Most robust approach
- Recommended for complex missions
## Geofencing Configuration
Edit `config/geofence_params.yaml`:
```yaml
geofence:
enabled: true
use_gps: true # GPS ONLY for geofence
# Define boundaries (GPS coordinates)
fence_type: "polygon" # or "circle"
# Polygon fence (lat/lon points)
polygon_points:
- {lat: 47.397742, lon: 8.545594} # Point 1
- {lat: 47.398242, lon: 8.545594} # Point 2
- {lat: 47.398242, lon: 8.546094} # Point 3
- {lat: 47.397742, lon: 8.546094} # Point 4
# Or circle fence
center_lat: 47.397742
center_lon: 8.545594
radius_meters: 100
# Actions on breach
action: "RTL" # Return to launch
max_altitude: 50 # meters
```
## Example Mission (Relative Coordinates)
```python
# Example: Navigate to visual landmark
# Define mission in RELATIVE coordinates
mission_waypoints = [
{"x": 0, "y": 0, "z": 5}, # Takeoff to 5m
{"x": 10, "y": 0, "z": 5}, # Move 10m forward
{"x": 10, "y": 5, "z": 5}, # Move 5m right
{"x": 0, "y": 5, "z": 5}, # Return to start (offset)
{"x": 0, "y": 0, "z": 5}, # Back to takeoff point
{"x": 0, "y": 0, "z": 0}, # Land
]
# GPS is NEVER used for these waypoints
# Position estimated from visual odometry
``` ```
## Project Structure ## Project Structure
- `launch/` - ROS 2 launch files ```
- `worlds/` - Gazebo world files (indoor, urban) simulation/
- `models/` - Robot models (Iris with cameras, UGV) ├── setup.sh # One-command installation
- `src/vision/` - Visual odometry, optical flow ├── activate_venv.sh # Environment activation
- `src/localization/` - Position estimation, sensor fusion ├── scripts/
- `src/navigation/` - Path planning (relative coordinates) │ ├── run_simulation.sh # Launch full simulation
- `src/safety/` - Geofencing (GPS-based) │ └── kill_simulation.sh # Stop all processes
- `config/` - Configuration files ├── worlds/ # Gazebo world files
├── models/ # UAV and UGV models
├── src/
│ ├── vision/ # Visual odometry, optical flow
│ ├── localization/ # EKF sensor fusion
│ ├── navigation/ # Path planning
│ ├── control/ # UAV/UGV controllers
│ └── safety/ # Geofencing
├── config/ # Configuration files
└── docs/ # Documentation
```
## Documentation ## Documentation
- [Setup Guide](docs/setup_guide.md) - Linux installation - [Setup Guide](docs/setup_guide.md) - Detailed installation
- [WSL Setup Guide](docs/wsl_setup_guide.md) - Windows WSL2 installation - [WSL Setup Guide](docs/wsl_setup_guide.md) - Windows WSL2
- [Usage Guide](docs/usage.md) - [Usage Guide](docs/usage.md) - How to use
- [Architecture Overview](docs/architecture.md) - [Architecture](docs/architecture.md) - System design
- [GPS-Denied Navigation](docs/gps_denied_navigation.md) - [GPS-Denied Navigation](docs/gps_denied_navigation.md) - Navigation approach
- [Troubleshooting](docs/troubleshooting.md) - [Troubleshooting](docs/troubleshooting.md) - Common issues
## Simulation Options
```bash
# Default (ArduPilot Iris world)
bash scripts/run_simulation.sh
# Custom world
bash scripts/run_simulation.sh --world worlds/indoor_warehouse.world
# Rover instead of copter
bash scripts/run_simulation.sh --vehicle rover
# Software rendering (WSL/no GPU)
bash scripts/run_simulation.sh --software-render
```
## Key Differences from GPS Navigation ## Key Differences from GPS Navigation
@@ -229,25 +183,3 @@ mission_waypoints = [
| Indoor Capability | No | Yes | | Indoor Capability | No | Yes |
| Drift | Minimal | Accumulates over time | | Drift | Minimal | Accumulates over time |
| Geofencing | GPS-based | GPS-based (safety only) | | Geofencing | GPS-based | GPS-based (safety only) |
| Use Cases | Outdoor, open sky | Indoor, urban, GPS-jammed |
## Running Different Scenarios
```bash
# Indoor warehouse (no GPS available)
bash scripts/run_simulation.sh --world worlds/indoor_warehouse.world
# Urban canyon (degraded GPS)
bash scripts/run_simulation.sh --world worlds/urban_canyon.world
# Open outdoor (GPS available but not used for nav)
bash scripts/run_simulation.sh --world worlds/empty_custom.world
```
## License
MIT License
## Contributing
Contributions welcome! Please ensure all navigation remains GPS-denied (except geofencing).

View File

@@ -0,0 +1,13 @@
<?xml version="1.0"?>
<model>
<name>Iris with ArduPilot</name>
<version>1.0</version>
<sdf version="1.6">model.sdf</sdf>
<author>
<name>UAV-UGV Simulation</name>
</author>
<description>
Iris quadcopter with ArduPilot SITL plugin for GPS-denied navigation testing.
Includes forward and downward cameras for visual odometry.
</description>
</model>

View File

@@ -0,0 +1,311 @@
<?xml version="1.0" ?>
<sdf version="1.6">
<model name="iris_with_ardupilot">
<pose>0 0 0.194923 0 0 0</pose>
<link name="base_link">
<inertial>
<pose>0 0 0 0 0 0</pose>
<mass>1.5</mass>
<inertia>
<ixx>0.029125</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>0.029125</iyy>
<iyz>0</iyz>
<izz>0.055225</izz>
</inertia>
</inertial>
<collision name="base_collision">
<pose>0 0 -0.08 0 0 0</pose>
<geometry>
<box><size>0.47 0.47 0.11</size></box>
</geometry>
</collision>
<visual name="base_visual">
<pose>0 0 0 0 0 0</pose>
<geometry>
<mesh>
<uri>model://iris/meshes/iris.dae</uri>
<scale>1 1 1</scale>
</mesh>
</geometry>
</visual>
<!-- Fallback visual if mesh not found -->
<visual name="body_box">
<pose>0 0 0 0 0 0</pose>
<geometry>
<box><size>0.3 0.3 0.1</size></box>
</geometry>
<material>
<ambient>0.2 0.2 0.8 1</ambient>
<diffuse>0.2 0.2 0.8 1</diffuse>
</material>
</visual>
<!-- IMU Sensor -->
<sensor name="imu_sensor" type="imu">
<always_on>true</always_on>
<update_rate>200</update_rate>
<imu>
<angular_velocity>
<x><noise type="gaussian"><mean>0</mean><stddev>0.0003</stddev></noise></x>
<y><noise type="gaussian"><mean>0</mean><stddev>0.0003</stddev></noise></y>
<z><noise type="gaussian"><mean>0</mean><stddev>0.0003</stddev></noise></z>
</angular_velocity>
<linear_acceleration>
<x><noise type="gaussian"><mean>0</mean><stddev>0.017</stddev></noise></x>
<y><noise type="gaussian"><mean>0</mean><stddev>0.017</stddev></noise></y>
<z><noise type="gaussian"><mean>0</mean><stddev>0.017</stddev></noise></z>
</linear_acceleration>
</imu>
</sensor>
</link>
<!-- Rotor 0 (Front Right CW) -->
<link name="rotor_0">
<pose>0.13 -0.22 0.023 0 0 0</pose>
<inertial>
<mass>0.025</mass>
<inertia>
<ixx>9.75e-06</ixx><ixy>0</ixy><ixz>0</ixz>
<iyy>0.000166704</iyy><iyz>0</iyz><izz>0.000167604</izz>
</inertia>
</inertial>
<visual name="visual">
<geometry><cylinder><radius>0.1</radius><length>0.01</length></cylinder></geometry>
<material><ambient>0.1 0.1 0.1 1</ambient></material>
</visual>
</link>
<joint name="rotor_0_joint" type="revolute">
<parent>base_link</parent>
<child>rotor_0</child>
<axis>
<xyz>0 0 1</xyz>
<limit><lower>-1e16</lower><upper>1e16</upper></limit>
</axis>
</joint>
<!-- Rotor 1 (Back Left CW) -->
<link name="rotor_1">
<pose>-0.13 0.22 0.023 0 0 0</pose>
<inertial>
<mass>0.025</mass>
<inertia>
<ixx>9.75e-06</ixx><ixy>0</ixy><ixz>0</ixz>
<iyy>0.000166704</iyy><iyz>0</iyz><izz>0.000167604</izz>
</inertia>
</inertial>
<visual name="visual">
<geometry><cylinder><radius>0.1</radius><length>0.01</length></cylinder></geometry>
<material><ambient>0.1 0.1 0.1 1</ambient></material>
</visual>
</link>
<joint name="rotor_1_joint" type="revolute">
<parent>base_link</parent>
<child>rotor_1</child>
<axis>
<xyz>0 0 1</xyz>
<limit><lower>-1e16</lower><upper>1e16</upper></limit>
</axis>
</joint>
<!-- Rotor 2 (Front Left CCW) -->
<link name="rotor_2">
<pose>0.13 0.22 0.023 0 0 0</pose>
<inertial>
<mass>0.025</mass>
<inertia>
<ixx>9.75e-06</ixx><ixy>0</ixy><ixz>0</ixz>
<iyy>0.000166704</iyy><iyz>0</iyz><izz>0.000167604</izz>
</inertia>
</inertial>
<visual name="visual">
<geometry><cylinder><radius>0.1</radius><length>0.01</length></cylinder></geometry>
<material><ambient>0.1 0.1 0.1 1</ambient></material>
</visual>
</link>
<joint name="rotor_2_joint" type="revolute">
<parent>base_link</parent>
<child>rotor_2</child>
<axis>
<xyz>0 0 1</xyz>
<limit><lower>-1e16</lower><upper>1e16</upper></limit>
</axis>
</joint>
<!-- Rotor 3 (Back Right CCW) -->
<link name="rotor_3">
<pose>-0.13 -0.22 0.023 0 0 0</pose>
<inertial>
<mass>0.025</mass>
<inertia>
<ixx>9.75e-06</ixx><ixy>0</ixy><ixz>0</ixz>
<iyy>0.000166704</iyy><iyz>0</iyz><izz>0.000167604</izz>
</inertia>
</inertial>
<visual name="visual">
<geometry><cylinder><radius>0.1</radius><length>0.01</length></cylinder></geometry>
<material><ambient>0.1 0.1 0.1 1</ambient></material>
</visual>
</link>
<joint name="rotor_3_joint" type="revolute">
<parent>base_link</parent>
<child>rotor_3</child>
<axis>
<xyz>0 0 1</xyz>
<limit><lower>-1e16</lower><upper>1e16</upper></limit>
</axis>
</joint>
<!-- Forward Camera for Visual Odometry -->
<link name="forward_camera_link">
<pose>0.1 0 0 0 0 0</pose>
<inertial>
<mass>0.01</mass>
<inertia>
<ixx>1e-5</ixx><ixy>0</ixy><ixz>0</ixz>
<iyy>1e-5</iyy><iyz>0</iyz><izz>1e-5</izz>
</inertia>
</inertial>
<visual name="visual">
<geometry><box><size>0.02 0.02 0.02</size></box></geometry>
<material><ambient>0 0 0 1</ambient></material>
</visual>
<sensor name="forward_camera" type="camera">
<camera>
<horizontal_fov>1.57</horizontal_fov>
<image>
<width>640</width>
<height>480</height>
<format>R8G8B8</format>
</image>
<clip><near>0.1</near><far>100</far></clip>
</camera>
<always_on>1</always_on>
<update_rate>30</update_rate>
<visualize>true</visualize>
<plugin name="camera_controller" filename="libgazebo_ros_camera.so">
<ros>
<namespace>/uav</namespace>
<remapping>image_raw:=camera/forward/image_raw</remapping>
<remapping>camera_info:=camera/forward/camera_info</remapping>
</ros>
<camera_name>forward_camera</camera_name>
<frame_name>forward_camera_link</frame_name>
</plugin>
</sensor>
</link>
<joint name="forward_camera_joint" type="fixed">
<parent>base_link</parent>
<child>forward_camera_link</child>
</joint>
<!-- Downward Camera for Optical Flow -->
<link name="downward_camera_link">
<pose>0 0 -0.05 0 1.5708 0</pose>
<inertial>
<mass>0.01</mass>
<inertia>
<ixx>1e-5</ixx><ixy>0</ixy><ixz>0</ixz>
<iyy>1e-5</iyy><iyz>0</iyz><izz>1e-5</izz>
</inertia>
</inertial>
<sensor name="downward_camera" type="camera">
<camera>
<horizontal_fov>1.2</horizontal_fov>
<image>
<width>320</width>
<height>240</height>
<format>R8G8B8</format>
</image>
<clip><near>0.1</near><far>50</far></clip>
</camera>
<always_on>1</always_on>
<update_rate>60</update_rate>
<visualize>false</visualize>
<plugin name="camera_controller" filename="libgazebo_ros_camera.so">
<ros>
<namespace>/uav</namespace>
<remapping>image_raw:=camera/downward/image_raw</remapping>
<remapping>camera_info:=camera/downward/camera_info</remapping>
</ros>
<camera_name>downward_camera</camera_name>
<frame_name>downward_camera_link</frame_name>
</plugin>
</sensor>
</link>
<joint name="downward_camera_joint" type="fixed">
<parent>base_link</parent>
<child>downward_camera_link</child>
</joint>
<!-- ArduPilot Plugin -->
<plugin name="ardupilot_plugin" filename="libArduPilotPlugin.so">
<fdm_addr>127.0.0.1</fdm_addr>
<fdm_port_in>9002</fdm_port_in>
<fdm_port_out>9003</fdm_port_out>
<modelXYZToAirplaneXForwardZDown>0 0 0 3.141593 0 0</modelXYZToAirplaneXForwardZDown>
<gazeboXYZToNED>0 0 0 3.141593 0 0</gazeboXYZToNED>
<imuName>iris_with_ardupilot::base_link::imu_sensor</imuName>
<connectionTimeoutMaxCount>5</connectionTimeoutMaxCount>
<!-- Motor configuration -->
<control channel="0">
<jointName>rotor_0_joint</jointName>
<type>VELOCITY</type>
<offset>0</offset>
<p_gain>0.20</p_gain>
<i_gain>0</i_gain>
<d_gain>0</d_gain>
<i_max>0</i_max>
<i_min>0</i_min>
<cmd_max>2.5</cmd_max>
<cmd_min>-2.5</cmd_min>
<multiplier>838</multiplier>
</control>
<control channel="1">
<jointName>rotor_1_joint</jointName>
<type>VELOCITY</type>
<offset>0</offset>
<p_gain>0.20</p_gain>
<i_gain>0</i_gain>
<d_gain>0</d_gain>
<i_max>0</i_max>
<i_min>0</i_min>
<cmd_max>2.5</cmd_max>
<cmd_min>-2.5</cmd_min>
<multiplier>838</multiplier>
</control>
<control channel="2">
<jointName>rotor_2_joint</jointName>
<type>VELOCITY</type>
<offset>0</offset>
<p_gain>0.20</p_gain>
<i_gain>0</i_gain>
<d_gain>0</d_gain>
<i_max>0</i_max>
<i_min>0</i_min>
<cmd_max>2.5</cmd_max>
<cmd_min>-2.5</cmd_min>
<multiplier>-838</multiplier>
</control>
<control channel="3">
<jointName>rotor_3_joint</jointName>
<type>VELOCITY</type>
<offset>0</offset>
<p_gain>0.20</p_gain>
<i_gain>0</i_gain>
<d_gain>0</d_gain>
<i_max>0</i_max>
<i_min>0</i_min>
<cmd_max>2.5</cmd_max>
<cmd_min>-2.5</cmd_min>
<multiplier>-838</multiplier>
</control>
</plugin>
</model>
</sdf>

View File

@@ -1,24 +1,90 @@
<?xml version="1.0" ?> <?xml version="1.0" ?>
<sdf version="1.6"> <sdf version="1.6">
<!-- Simple quadcopter model for testing without ArduPilot -->
<model name="iris_with_camera"> <model name="iris_with_camera">
<include> <pose>0 0 0.1 0 0 0</pose>
<uri>model://iris</uri>
</include>
<link name="forward_camera_link"> <!-- Base/Body -->
<pose>0.1 0 0 0 0 0</pose> <link name="base_link">
<inertial> <inertial>
<mass>0.01</mass> <mass>1.5</mass>
<inertia> <inertia>
<ixx>0.00001</ixx><ixy>0</ixy><ixz>0</ixz> <ixx>0.029125</ixx><ixy>0</ixy><ixz>0</ixz>
<iyy>0.00001</iyy><iyz>0</iyz><izz>0.00001</izz> <iyy>0.029125</iyy><iyz>0</iyz><izz>0.055225</izz>
</inertia> </inertia>
</inertial> </inertial>
<visual name="visual">
<geometry><box><size>0.02 0.02 0.02</size></box></geometry> <!-- Main body -->
<visual name="body_visual">
<geometry>
<box><size>0.3 0.3 0.1</size></box>
</geometry>
<material>
<ambient>0.2 0.2 0.8 1</ambient>
<diffuse>0.2 0.2 0.8 1</diffuse>
</material>
</visual>
<collision name="body_collision">
<geometry>
<box><size>0.3 0.3 0.1</size></box>
</geometry>
</collision>
<!-- Arms -->
<visual name="arm1_visual">
<pose>0.15 0.15 0 0 0 0.785</pose>
<geometry><box><size>0.3 0.02 0.02</size></box></geometry>
<material><ambient>0.3 0.3 0.3 1</ambient></material>
</visual>
<visual name="arm2_visual">
<pose>-0.15 0.15 0 0 0 -0.785</pose>
<geometry><box><size>0.3 0.02 0.02</size></box></geometry>
<material><ambient>0.3 0.3 0.3 1</ambient></material>
</visual>
<visual name="arm3_visual">
<pose>-0.15 -0.15 0 0 0 0.785</pose>
<geometry><box><size>0.3 0.02 0.02</size></box></geometry>
<material><ambient>0.3 0.3 0.3 1</ambient></material>
</visual>
<visual name="arm4_visual">
<pose>0.15 -0.15 0 0 0 -0.785</pose>
<geometry><box><size>0.3 0.02 0.02</size></box></geometry>
<material><ambient>0.3 0.3 0.3 1</ambient></material>
</visual>
<!-- Rotors -->
<visual name="rotor1">
<pose>0.22 0.22 0.05 0 0 0</pose>
<geometry><cylinder><radius>0.1</radius><length>0.01</length></cylinder></geometry>
<material><ambient>0.1 0.1 0.1 1</ambient></material>
</visual>
<visual name="rotor2">
<pose>-0.22 0.22 0.05 0 0 0</pose>
<geometry><cylinder><radius>0.1</radius><length>0.01</length></cylinder></geometry>
<material><ambient>0.1 0.1 0.1 1</ambient></material>
</visual>
<visual name="rotor3">
<pose>-0.22 -0.22 0.05 0 0 0</pose>
<geometry><cylinder><radius>0.1</radius><length>0.01</length></cylinder></geometry>
<material><ambient>0.1 0.1 0.1 1</ambient></material>
</visual>
<visual name="rotor4">
<pose>0.22 -0.22 0.05 0 0 0</pose>
<geometry><cylinder><radius>0.1</radius><length>0.01</length></cylinder></geometry>
<material><ambient>0.1 0.1 0.1 1</ambient></material>
</visual>
<!-- Forward camera (small black box) -->
<visual name="forward_camera_visual">
<pose>0.18 0 0 0 0 0</pose>
<geometry><box><size>0.03 0.03 0.03</size></box></geometry>
<material><ambient>0 0 0 1</ambient></material> <material><ambient>0 0 0 1</ambient></material>
</visual> </visual>
<!-- Forward Camera Sensor -->
<sensor name="forward_camera" type="camera"> <sensor name="forward_camera" type="camera">
<pose>0.18 0 0 0 0 0</pose>
<camera> <camera>
<horizontal_fov>1.57</horizontal_fov> <horizontal_fov>1.57</horizontal_fov>
<image> <image>
@@ -31,37 +97,11 @@
<always_on>1</always_on> <always_on>1</always_on>
<update_rate>30</update_rate> <update_rate>30</update_rate>
<visualize>true</visualize> <visualize>true</visualize>
<plugin name="camera_controller" filename="libgazebo_ros_camera.so">
<ros>
<namespace>/uav</namespace>
<remapping>image_raw:=camera/forward/image_raw</remapping>
<remapping>camera_info:=camera/forward/camera_info</remapping>
</ros>
<camera_name>forward_camera</camera_name>
<frame_name>forward_camera_link</frame_name>
</plugin>
</sensor> </sensor>
</link>
<!-- Downward Camera Sensor -->
<joint name="forward_camera_joint" type="fixed">
<parent>iris::base_link</parent>
<child>forward_camera_link</child>
</joint>
<link name="downward_camera_link">
<pose>0 0 -0.05 0 1.5708 0</pose>
<inertial>
<mass>0.01</mass>
<inertia>
<ixx>0.00001</ixx><ixy>0</ixy><ixz>0</ixz>
<iyy>0.00001</iyy><iyz>0</iyz><izz>0.00001</izz>
</inertia>
</inertial>
<visual name="visual">
<geometry><box><size>0.02 0.02 0.02</size></box></geometry>
<material><ambient>0.3 0.3 0.3 1</ambient></material>
</visual>
<sensor name="downward_camera" type="camera"> <sensor name="downward_camera" type="camera">
<pose>0 0 -0.06 0 1.5708 0</pose>
<camera> <camera>
<horizontal_fov>1.2</horizontal_fov> <horizontal_fov>1.2</horizontal_fov>
<image> <image>
@@ -74,55 +114,7 @@
<always_on>1</always_on> <always_on>1</always_on>
<update_rate>30</update_rate> <update_rate>30</update_rate>
<visualize>false</visualize> <visualize>false</visualize>
<plugin name="camera_controller" filename="libgazebo_ros_camera.so">
<ros>
<namespace>/uav</namespace>
<remapping>image_raw:=camera/downward/image_raw</remapping>
<remapping>camera_info:=camera/downward/camera_info</remapping>
</ros>
<camera_name>downward_camera</camera_name>
<frame_name>downward_camera_link</frame_name>
</plugin>
</sensor> </sensor>
</link> </link>
<joint name="downward_camera_joint" type="fixed">
<parent>iris::base_link</parent>
<child>downward_camera_link</child>
</joint>
<link name="rangefinder_link">
<pose>0 0 -0.06 0 1.5708 0</pose>
<inertial>
<mass>0.005</mass>
<inertia>
<ixx>0.000001</ixx><ixy>0</ixy><ixz>0</ixz>
<iyy>0.000001</iyy><iyz>0</iyz><izz>0.000001</izz>
</inertia>
</inertial>
<sensor name="rangefinder" type="ray">
<ray>
<scan>
<horizontal><samples>1</samples><resolution>1</resolution><min_angle>0</min_angle><max_angle>0</max_angle></horizontal>
</scan>
<range><min>0.1</min><max>10</max><resolution>0.01</resolution></range>
</ray>
<always_on>1</always_on>
<update_rate>30</update_rate>
<plugin name="range_plugin" filename="libgazebo_ros_ray_sensor.so">
<ros>
<namespace>/uav</namespace>
<remapping>~/out:=rangefinder/range</remapping>
</ros>
<output_type>sensor_msgs/Range</output_type>
<frame_name>rangefinder_link</frame_name>
</plugin>
</sensor>
</link>
<joint name="rangefinder_joint" type="fixed">
<parent>iris::base_link</parent>
<child>rangefinder_link</child>
</joint>
</model> </model>
</sdf> </sdf>

View File

@@ -1,7 +1,9 @@
#!/bin/bash #!/bin/bash
# Full simulation launch script with ArduPilot SITL
# This script launches Gazebo, ArduPilot SITL, and MAVROS
set -e set -e
# Colors
RED='\033[0;31m' RED='\033[0;31m'
GREEN='\033[0;32m' GREEN='\033[0;32m'
YELLOW='\033[1;33m' YELLOW='\033[1;33m'
@@ -35,16 +37,26 @@ done
if [ -z "$ROS_DISTRO" ]; then if [ -z "$ROS_DISTRO" ]; then
echo -e "${RED}ERROR: No ROS 2 installation found!${NC}" 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" echo "Please install ROS 2 first. See docs/setup_guide.md"
exit 1 exit 1
fi fi
echo -e "${GREEN}Using ROS 2: $ROS_DISTRO${NC}" echo -e "${GREEN}Using ROS 2: $ROS_DISTRO${NC}"
# Source ROS 2 # Check ArduPilot installation
ARDUPILOT_HOME="${ARDUPILOT_HOME:-$HOME/ardupilot}"
if [ ! -d "$ARDUPILOT_HOME" ]; then
echo -e "${RED}ERROR: ArduPilot not found at $ARDUPILOT_HOME${NC}"
echo ""
echo "Please install ArduPilot first:"
echo " bash scripts/install_ardupilot.sh"
echo ""
exit 1
fi
# Source environments
source /opt/ros/${ROS_DISTRO}/setup.bash source /opt/ros/${ROS_DISTRO}/setup.bash
# Source Gazebo setup (CRITICAL for shader paths)
if [ -f /usr/share/gazebo/setup.bash ]; then if [ -f /usr/share/gazebo/setup.bash ]; then
source /usr/share/gazebo/setup.bash source /usr/share/gazebo/setup.bash
elif [ -f /usr/share/gazebo-11/setup.bash ]; then elif [ -f /usr/share/gazebo-11/setup.bash ]; then
@@ -52,9 +64,10 @@ elif [ -f /usr/share/gazebo-11/setup.bash ]; then
fi fi
# Parse arguments # Parse arguments
WORLD="" WORLD="$PROJECT_DIR/worlds/iris_runway.world"
VEHICLE="copter"
USE_SOFTWARE_RENDER=false USE_SOFTWARE_RENDER=false
HEADLESS=false INSTANCE=0
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case $1 in case $1 in
@@ -62,34 +75,32 @@ while [[ $# -gt 0 ]]; do
WORLD="$2" WORLD="$2"
shift 2 shift 2
;; ;;
--headless) --vehicle)
HEADLESS=true VEHICLE="$2"
shift shift 2
;; ;;
--no-gpu|--software-render) --software-render)
USE_SOFTWARE_RENDER=true USE_SOFTWARE_RENDER=true
shift shift
;; ;;
--instance)
INSTANCE="$2"
shift 2
;;
--help) --help)
echo "Usage: $0 [OPTIONS] [WORLD_FILE]" echo "Usage: $0 [OPTIONS]"
echo "" echo ""
echo "Options:" echo "Options:"
echo " --world FILE Specify world file (default: empty_custom.world)" echo " --world FILE World file (default: iris_runway.world)"
echo " --headless Run without GUI (gzserver only)" echo " --vehicle TYPE Vehicle type: copter, rover (default: copter)"
echo " --software-render Force software rendering (recommended for WSL)" echo " --software-render Force software rendering (for WSL)"
echo " --help Show this help" echo " --instance N Vehicle instance number (default: 0)"
echo "" echo " --help Show this help"
echo "Examples:"
echo " $0 # Default world"
echo " $0 worlds/indoor_warehouse.world # Indoor environment"
echo " $0 --software-render # For WSL without GPU"
exit 0 exit 0
;; ;;
*) *)
if [ -f "$1" ]; then if [ -f "$1" ]; then
WORLD="$1" WORLD="$1"
elif [ -f "$PROJECT_DIR/$1" ]; then
WORLD="$PROJECT_DIR/$1"
elif [ -f "$PROJECT_DIR/worlds/$1" ]; then elif [ -f "$PROJECT_DIR/worlds/$1" ]; then
WORLD="$PROJECT_DIR/worlds/$1" WORLD="$PROJECT_DIR/worlds/$1"
fi fi
@@ -98,109 +109,172 @@ while [[ $# -gt 0 ]]; do
esac esac
done done
# Default world
if [ -z "$WORLD" ]; then
WORLD="$PROJECT_DIR/worlds/empty_custom.world"
fi
# Validate world file
if [ ! -f "$WORLD" ]; then
echo -e "${RED}ERROR: World file not found: $WORLD${NC}"
echo "Available worlds:"
ls -1 "$PROJECT_DIR/worlds/"*.world 2>/dev/null || echo " (none found)"
exit 1
fi
# Setup Gazebo paths # Setup Gazebo paths
export GAZEBO_MODEL_PATH="$PROJECT_DIR/models:${GAZEBO_MODEL_PATH:-}" export GAZEBO_MODEL_PATH="$PROJECT_DIR/models:${GAZEBO_MODEL_PATH:-}"
export GAZEBO_RESOURCE_PATH="$PROJECT_DIR/worlds:${GAZEBO_RESOURCE_PATH:-}" export GAZEBO_RESOURCE_PATH="$PROJECT_DIR/worlds:${GAZEBO_RESOURCE_PATH:-}"
# ArduPilot Gazebo paths (if installed)
if [ -d "$HOME/ardupilot_gazebo" ]; then if [ -d "$HOME/ardupilot_gazebo" ]; then
export GAZEBO_MODEL_PATH="$HOME/ardupilot_gazebo/models:$GAZEBO_MODEL_PATH" export GAZEBO_MODEL_PATH="$HOME/ardupilot_gazebo/models:$GAZEBO_MODEL_PATH"
export GAZEBO_RESOURCE_PATH="$HOME/ardupilot_gazebo/worlds:$GAZEBO_RESOURCE_PATH" export GAZEBO_RESOURCE_PATH="$HOME/ardupilot_gazebo/worlds:$GAZEBO_RESOURCE_PATH"
fi fi
# WSL-specific setup # WSL/Display setup
if $IS_WSL; then if $IS_WSL; then
# Source WSL environment if exists
if [ -f "$PROJECT_DIR/wsl_env.sh" ]; then if [ -f "$PROJECT_DIR/wsl_env.sh" ]; then
source "$PROJECT_DIR/wsl_env.sh" source "$PROJECT_DIR/wsl_env.sh"
fi fi
# Set DISPLAY if not set
if [ -z "$DISPLAY" ]; then if [ -z "$DISPLAY" ]; then
if [ -d "/mnt/wslg" ]; then export DISPLAY=:0
export DISPLAY=:0
else
export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0
fi
fi fi
echo -e "${BLUE}DISPLAY: $DISPLAY${NC}" echo -e "${BLUE}DISPLAY: $DISPLAY${NC}"
# Force software rendering in WSL by default if having issues
if ! $USE_SOFTWARE_RENDER; then
echo -e "${YELLOW}TIP: If Gazebo crashes or has rendering issues, use --software-render${NC}"
fi
fi fi
# Apply software rendering if requested or in WSL with issues
if $USE_SOFTWARE_RENDER; then if $USE_SOFTWARE_RENDER; then
echo -e "${YELLOW}Using software rendering${NC}" echo -e "${YELLOW}Using software rendering${NC}"
export LIBGL_ALWAYS_SOFTWARE=1 export LIBGL_ALWAYS_SOFTWARE=1
export MESA_GL_VERSION_OVERRIDE=3.3 export MESA_GL_VERSION_OVERRIDE=3.3
export MESA_GLSL_VERSION_OVERRIDE=330
fi fi
# Cleanup function # Cleanup function
cleanup() { cleanup() {
echo "" echo ""
echo -e "${YELLOW}Shutting down simulation...${NC}" echo -e "${YELLOW}Shutting down simulation...${NC}"
# Kill processes
pkill -f "sim_vehicle.py" 2>/dev/null || true
pkill -f "mavproxy" 2>/dev/null || true
pkill -f "ArduCopter" 2>/dev/null || true
pkill -f "ArduRover" 2>/dev/null || true
pkill -f "gzserver" 2>/dev/null || true pkill -f "gzserver" 2>/dev/null || true
pkill -f "gzclient" 2>/dev/null || true pkill -f "gzclient" 2>/dev/null || true
pkill -f "gazebo" 2>/dev/null || true pkill -f "gazebo" 2>/dev/null || true
sleep 1 pkill -f "mavros" 2>/dev/null || true
sleep 2
echo -e "${GREEN}Cleanup complete.${NC}" echo -e "${GREEN}Cleanup complete.${NC}"
} }
trap cleanup EXIT INT TERM trap cleanup EXIT INT TERM
# Activate virtual environment if exists # Activate virtual environment
if [ -f "$PROJECT_DIR/venv/bin/activate" ]; then if [ -f "$PROJECT_DIR/venv/bin/activate" ]; then
source "$PROJECT_DIR/venv/bin/activate" source "$PROJECT_DIR/venv/bin/activate"
fi fi
# Source workspace if built # Use ardupilot_gazebo iris world if no custom world specified
if [ -f "$PROJECT_DIR/../install/setup.bash" ]; then if [ ! -f "$WORLD" ]; then
source "$PROJECT_DIR/../install/setup.bash" if [ -f "$HOME/ardupilot_gazebo/worlds/iris_arducopter_runway.world" ]; then
elif [ -f "$PROJECT_DIR/install/setup.bash" ]; then WORLD="$HOME/ardupilot_gazebo/worlds/iris_arducopter_runway.world"
source "$PROJECT_DIR/install/setup.bash"
fi
echo ""
echo -e "${GREEN}Starting simulation with world: $(basename $WORLD)${NC}"
echo -e "${BLUE}World path: $WORLD${NC}"
echo ""
# Check if ROS package exists
ROS_PKG_EXISTS=false
if ros2 pkg list 2>/dev/null | grep -q "uav_ugv_simulation"; then
ROS_PKG_EXISTS=true
fi
# Launch simulation
if $ROS_PKG_EXISTS; then
echo -e "${GREEN}Launching via ROS 2...${NC}"
ros2 launch uav_ugv_simulation full_simulation.launch.py world:="$WORLD"
else
echo -e "${YELLOW}ROS package not built. Launching Gazebo directly...${NC}"
echo -e "${BLUE}To build the package: cd ~/ros2_ws && colcon build --packages-select uav_ugv_simulation${NC}"
echo ""
if $HEADLESS; then
gzserver --verbose "$WORLD"
else else
gazebo --verbose "$WORLD" echo -e "${RED}ERROR: World file not found: $WORLD${NC}"
exit 1
fi fi
fi fi
echo ""
echo -e "${GREEN}Configuration:${NC}"
echo " Vehicle: $VEHICLE"
echo " World: $(basename $WORLD)"
echo " Instance: $INSTANCE"
echo ""
# Calculate ports
MAVLINK_PORT=$((14550 + INSTANCE * 10))
SITL_PORT=$((5760 + INSTANCE * 10))
# Start Gazebo in background
echo -e "${GREEN}Starting Gazebo...${NC}"
gazebo --verbose "$WORLD" &
GAZEBO_PID=$!
sleep 5
# Check if Gazebo started
if ! kill -0 $GAZEBO_PID 2>/dev/null; then
echo -e "${RED}ERROR: Gazebo failed to start${NC}"
exit 1
fi
echo -e "${GREEN}Gazebo running (PID: $GAZEBO_PID)${NC}"
# Start ArduPilot SITL
echo -e "${GREEN}Starting ArduPilot SITL...${NC}"
cd "$ARDUPILOT_HOME"
if [ "$VEHICLE" = "copter" ]; then
VEHICLE_DIR="ArduCopter"
FRAME="gazebo-iris"
elif [ "$VEHICLE" = "rover" ]; then
VEHICLE_DIR="Rover"
FRAME="gazebo-rover"
else
VEHICLE_DIR="ArduCopter"
FRAME="gazebo-iris"
fi
cd "$ARDUPILOT_HOME/$VEHICLE_DIR"
# Start sim_vehicle.py in background
python3 "$ARDUPILOT_HOME/Tools/autotest/sim_vehicle.py" \
-v "$VEHICLE_DIR" \
-f "$FRAME" \
--no-mavproxy \
-I "$INSTANCE" \
--no-rebuild \
&
SITL_PID=$!
sleep 10
# Check if SITL started
if ! kill -0 $SITL_PID 2>/dev/null; then
echo -e "${RED}ERROR: ArduPilot SITL failed to start${NC}"
exit 1
fi
echo -e "${GREEN}ArduPilot SITL running (PID: $SITL_PID)${NC}"
# Start MAVROS
echo -e "${GREEN}Starting MAVROS...${NC}"
ros2 run mavros mavros_node --ros-args \
-p fcu_url:="udp://127.0.0.1:${MAVLINK_PORT}@" \
-p gcs_url:="" \
-p target_system_id:=1 \
-p target_component_id:=1 \
&>/dev/null &
MAVROS_PID=$!
sleep 5
echo ""
echo -e "${GREEN}==========================================${NC}"
echo -e "${GREEN} Simulation Running${NC}"
echo -e "${GREEN}==========================================${NC}"
echo ""
echo -e "${BLUE}Components:${NC}"
echo " - Gazebo: PID $GAZEBO_PID"
echo " - ArduPilot SITL: PID $SITL_PID"
echo " - MAVROS: PID $MAVROS_PID"
echo ""
echo -e "${BLUE}MAVROS Topics:${NC}"
echo " ros2 topic list | grep mavros"
echo ""
echo -e "${BLUE}Control UAV:${NC}"
echo " # Arm"
echo " ros2 service call /mavros/cmd/arming mavros_msgs/srv/CommandBool \"{value: true}\""
echo ""
echo " # Set mode to GUIDED"
echo " ros2 service call /mavros/set_mode mavros_msgs/srv/SetMode \"{base_mode: 0, custom_mode: 'GUIDED'}\""
echo ""
echo " # Takeoff to 5 meters"
echo " ros2 service call /mavros/cmd/takeoff mavros_msgs/srv/CommandTOL \"{altitude: 5}\""
echo ""
echo " # Send position setpoint (x, y, z in meters)"
echo " ros2 topic pub /mavros/setpoint_position/local geometry_msgs/PoseStamped \\"
echo " \"{header: {frame_id: 'map'}, pose: {position: {x: 10, y: 5, z: 5}}}\""
echo ""
echo -e "${YELLOW}Press Ctrl+C to stop simulation${NC}"
echo ""
# Wait for all processes
wait

View File

@@ -1,25 +0,0 @@
#!/bin/bash
echo "Setting up NVIDIA GPU for Gazebo..."
if ! command -v nvidia-smi &> /dev/null; then
echo "NVIDIA driver not found. Skipping GPU setup."
exit 0
fi
echo "NVIDIA GPU detected:"
nvidia-smi --query-gpu=name,driver_version --format=csv,noheader
export __NV_PRIME_RENDER_OFFLOAD=1
export __GLX_VENDOR_LIBRARY_NAME=nvidia
export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json
if [ -f /usr/lib/x86_64-linux-gnu/libEGL_nvidia.so.0 ]; then
export __EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/10_nvidia.json
fi
echo "NVIDIA GPU environment configured."
echo ""
echo "Add these to your ~/.bashrc for permanent setup:"
echo " export __NV_PRIME_RENDER_OFFLOAD=1"
echo " export __GLX_VENDOR_LIBRARY_NAME=nvidia"

View File

@@ -1,174 +0,0 @@
#!/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 ""

552
setup.sh
View File

@@ -1,17 +1,21 @@
#!/bin/bash #!/bin/bash
# UAV-UGV Simulation - Complete Installation Script
# Installs everything needed for GPS-denied navigation simulation
# Compatible with Ubuntu 22.04/24.04 and WSL2
set -e set -e
# Colors for output
RED='\033[0;31m' RED='\033[0;31m'
GREEN='\033[0;32m' GREEN='\033[0;32m'
YELLOW='\033[1;33m' YELLOW='\033[1;33m'
BLUE='\033[0;34m' BLUE='\033[0;34m'
NC='\033[0m' # No Color CYAN='\033[0;36m'
NC='\033[0m'
print_header() { print_header() {
echo ""
echo -e "${BLUE}==========================================${NC}" echo -e "${BLUE}==========================================${NC}"
echo -e "${BLUE} UAV-UGV Simulation Setup${NC}" echo -e "${BLUE} $1${NC}"
echo -e "${BLUE} GPS-Denied Navigation with Geofencing${NC}"
echo -e "${BLUE}==========================================${NC}" echo -e "${BLUE}==========================================${NC}"
echo "" echo ""
} }
@@ -20,6 +24,10 @@ print_step() {
echo -e "${GREEN}[$1/$TOTAL_STEPS] $2${NC}" echo -e "${GREEN}[$1/$TOTAL_STEPS] $2${NC}"
} }
print_info() {
echo -e "${CYAN}INFO: $1${NC}"
}
print_warning() { print_warning() {
echo -e "${YELLOW}WARNING: $1${NC}" echo -e "${YELLOW}WARNING: $1${NC}"
} }
@@ -28,21 +36,14 @@ print_error() {
echo -e "${RED}ERROR: $1${NC}" echo -e "${RED}ERROR: $1${NC}"
} }
print_info() {
echo -e "${BLUE}INFO: $1${NC}"
}
# Detect environment # Detect environment
detect_environment() { detect_environment() {
IS_WSL=false IS_WSL=false
IS_WSL2=false IS_WSL2=false
UBUNTU_VERSION=""
ROS_DISTRO=""
# Detect WSL
if grep -qEi "(microsoft|wsl)" /proc/version 2>/dev/null; then if grep -qEi "(microsoft|wsl)" /proc/version 2>/dev/null; then
IS_WSL=true IS_WSL=true
if grep -qi "wsl2" /proc/version 2>/dev/null || [ -f /run/WSL ]; then if [ -f /run/WSL ] || grep -qi "wsl2" /proc/version 2>/dev/null; then
IS_WSL2=true IS_WSL2=true
fi fi
fi fi
@@ -54,330 +55,319 @@ detect_environment() {
UBUNTU_CODENAME="$VERSION_CODENAME" UBUNTU_CODENAME="$VERSION_CODENAME"
fi fi
# Determine ROS distro based on Ubuntu version # Determine ROS distro
case "$UBUNTU_VERSION" in case "$UBUNTU_VERSION" in
"22.04") "22.04") ROS_DISTRO="humble" ;;
ROS_DISTRO="humble" "24.04") ROS_DISTRO="jazzy" ;;
;; "20.04") ROS_DISTRO="galactic" ;;
"24.04") *) ROS_DISTRO="humble" ;;
ROS_DISTRO="jazzy"
;;
"20.04")
ROS_DISTRO="galactic"
;;
*)
ROS_DISTRO="humble" # Default fallback
;;
esac 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 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
check_ros2_installed() { cd "$SCRIPT_DIR"
if [ -d "/opt/ros/$ROS_DISTRO" ]; then
return 0 print_header "UAV-UGV Simulation - Complete Setup"
else echo "GPS-Denied Navigation with Geofencing"
return 1 echo ""
detect_environment
echo -e "${CYAN}Detected Environment:${NC}"
echo " Ubuntu: $UBUNTU_VERSION ($UBUNTU_CODENAME)"
echo " WSL: $IS_WSL | WSL2: $IS_WSL2"
echo " ROS 2 Target: $ROS_DISTRO"
echo ""
TOTAL_STEPS=10
STEP=1
# ============================================================================
# STEP 1: System Update
# ============================================================================
print_step $STEP "Updating system packages"
sudo apt-get update
sudo apt-get upgrade -y
((STEP++))
# ============================================================================
# STEP 2: Install Base Dependencies
# ============================================================================
print_step $STEP "Installing base dependencies"
sudo apt-get install -y \
curl \
gnupg \
lsb-release \
software-properties-common \
wget \
git \
gitk \
build-essential \
cmake \
python3-dev \
python3-pip \
python3-venv \
python3-opencv \
python3-matplotlib \
python3-lxml \
python3-yaml \
python3-scipy \
python3-future \
libopencv-dev \
libxml2-dev \
libxslt1-dev \
ccache \
gawk \
libtool-bin
# WSL-specific packages
if $IS_WSL; then
print_info "Installing WSL GUI support packages"
sudo apt-get install -y \
x11-apps \
x11-xserver-utils \
dbus-x11 \
mesa-utils \
libgl1-mesa-glx
fi
((STEP++))
# ============================================================================
# STEP 3: Install ROS 2
# ============================================================================
print_step $STEP "Installing ROS 2 $ROS_DISTRO"
if [ ! -d "/opt/ros/$ROS_DISTRO" ]; then
# Add ROS 2 repository
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 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] \ 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" | \ http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
sudo apt-get update sudo apt-get update
} sudo apt-get install -y ros-${ROS_DISTRO}-desktop python3-colcon-common-extensions
# 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 else
# WSL1 print_info "ROS 2 $ROS_DISTRO already installed"
export DISPLAY=localhost:0
fi 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"
# Detect environment
detect_environment
# 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++))
# Step: WSL-specific setup # ============================================================================
if $IS_WSL; then # STEP 4: Install ROS 2 Packages
print_step $STEP "Setting up WSL environment..." # ============================================================================
setup_wsl print_step $STEP "Installing ROS 2 packages"
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 \ sudo apt-get install -y \
python3-pip \ ros-${ROS_DISTRO}-mavros \
python3-venv \ ros-${ROS_DISTRO}-mavros-extras \
python3-opencv \ ros-${ROS_DISTRO}-cv-bridge \
libopencv-dev \ ros-${ROS_DISTRO}-image-transport \
python3-colcon-common-extensions \ ros-${ROS_DISTRO}-tf2 \
build-essential \ ros-${ROS_DISTRO}-tf2-ros \
cmake \ ros-${ROS_DISTRO}-tf2-geometry-msgs \
git || true ros-${ROS_DISTRO}-gazebo-ros-pkgs 2>/dev/null || \
((STEP++)) print_warning "Some ROS packages not available for $ROS_DISTRO"
# Step: Install ROS 2 packages # Install GeographicLib datasets for MAVROS
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
# 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" GEOGRAPHICLIB_SCRIPT="/opt/ros/${ROS_DISTRO}/lib/mavros/install_geographiclib_datasets.sh"
if [ -f "$GEOGRAPHICLIB_SCRIPT" ]; then if [ -f "$GEOGRAPHICLIB_SCRIPT" ]; then
if [ ! -f /usr/share/GeographicLib/geoids/egm96-5.pgm ]; then if [ ! -f /usr/share/GeographicLib/geoids/egm96-5.pgm ]; then
sudo "$GEOGRAPHICLIB_SCRIPT" || print_warning "GeographicLib datasets installation failed" print_info "Installing GeographicLib datasets (this may take a minute)"
else sudo "$GEOGRAPHICLIB_SCRIPT" || print_warning "GeographicLib installation failed"
print_info "GeographicLib datasets already installed"
fi fi
else
print_warning "MAVROS not installed, skipping GeographicLib datasets"
fi fi
((STEP++)) ((STEP++))
# Step: Create Python virtual environment # ============================================================================
print_step $STEP "Creating Python virtual environment..." # STEP 5: Install Gazebo
# ============================================================================
print_step $STEP "Installing Gazebo"
sudo apt-get install -y gazebo libgazebo-dev || \
sudo apt-get install -y gazebo11 libgazebo11-dev || \
print_warning "Gazebo installation may require manual setup"
((STEP++))
# ============================================================================
# STEP 6: Install ArduPilot SITL
# ============================================================================
print_step $STEP "Installing ArduPilot SITL"
ARDUPILOT_HOME="$HOME/ardupilot"
if [ ! -d "$ARDUPILOT_HOME" ]; then
print_info "Cloning ArduPilot repository..."
cd "$HOME"
git clone --recurse-submodules https://github.com/ArduPilot/ardupilot.git
cd ardupilot
git submodule update --init --recursive
else
print_info "ArduPilot already exists, updating..."
cd "$ARDUPILOT_HOME"
git fetch origin
git submodule update --init --recursive
fi
# Install ArduPilot prerequisites
print_info "Installing ArduPilot prerequisites..."
cd "$ARDUPILOT_HOME"
USER_NONINTERACTIVE=1 Tools/environment_install/install-prereqs-ubuntu.sh -y || true
# Reload profile
. ~/.profile 2>/dev/null || true
# Build ArduPilot SITL
print_info "Building ArduPilot SITL (this may take several minutes)..."
cd "$ARDUPILOT_HOME"
./waf configure --board sitl
./waf copter
./waf rover
((STEP++))
# ============================================================================
# STEP 7: Install ardupilot_gazebo Plugin
# ============================================================================
print_step $STEP "Installing ardupilot_gazebo plugin"
ARDUPILOT_GAZEBO_HOME="$HOME/ardupilot_gazebo"
if [ ! -d "$ARDUPILOT_GAZEBO_HOME" ]; then
print_info "Cloning ardupilot_gazebo..."
cd "$HOME"
git clone https://github.com/ArduPilot/ardupilot_gazebo.git
else
print_info "ardupilot_gazebo already exists, updating..."
cd "$ARDUPILOT_GAZEBO_HOME"
git pull origin main || true
fi
cd "$ARDUPILOT_GAZEBO_HOME"
mkdir -p build && cd build
cmake ..
make -j$(nproc)
sudo make install
((STEP++))
# ============================================================================
# STEP 8: Setup Python Virtual Environment
# ============================================================================
print_step $STEP "Setting up Python environment"
cd "$SCRIPT_DIR"
if [ ! -d "venv" ]; then if [ ! -d "venv" ]; then
python3 -m venv venv python3 -m venv venv
fi fi
source venv/bin/activate source venv/bin/activate
# Upgrade pip and install dependencies
pip install --upgrade pip pip install --upgrade pip
pip install -r requirements.txt || { pip install -r requirements.txt || print_warning "Some Python packages failed"
print_warning "Some Python packages failed to install. Check requirements.txt" deactivate
}
((STEP++)) ((STEP++))
# Step: Build ROS 2 package # ============================================================================
print_step $STEP "Building ROS 2 package..." # STEP 9: Configure Environment
if [ -f "/opt/ros/${ROS_DISTRO}/setup.bash" ]; then # ============================================================================
source /opt/ros/${ROS_DISTRO}/setup.bash print_step $STEP "Configuring environment"
# Try to build if in a ROS workspace # Create WSL environment file
if [ -d "$SCRIPT_DIR/../src" ] || [ -f "$SCRIPT_DIR/package.xml" ]; then if $IS_WSL; then
cd "$SCRIPT_DIR/.." cat > "$SCRIPT_DIR/wsl_env.sh" << 'WSLEOF'
colcon build --packages-select uav_ugv_simulation --symlink-install 2>/dev/null || { #!/bin/bash
print_warning "Colcon build skipped. To build manually:" # WSL Environment for UAV-UGV Simulation
print_info " cd ~/ros2_ws && colcon build --packages-select uav_ugv_simulation"
} if [ -d "/mnt/wslg" ]; then
cd "$SCRIPT_DIR" export DISPLAY=:0
fi
else else
print_warning "ROS 2 not found, skipping package build" export DISPLAY=$(cat /etc/resolv.conf 2>/dev/null | grep nameserver | awk '{print $2}'):0
fi fi
((STEP++))
# Step: Make scripts executable and create activation script export LIBGL_ALWAYS_INDIRECT=0
print_step $STEP "Finalizing setup..." export MESA_GL_VERSION_OVERRIDE=3.3
chmod +x scripts/*.sh 2>/dev/null || true export MESA_GLSL_VERSION_OVERRIDE=330
export OGRE_RTT_MODE=Copy
# Source Gazebo setup
[ -f /usr/share/gazebo/setup.bash ] && source /usr/share/gazebo/setup.bash
[ -f /usr/share/gazebo-11/setup.bash ] && source /usr/share/gazebo-11/setup.bash
WSLEOF
chmod +x "$SCRIPT_DIR/wsl_env.sh"
fi
# Create activation script # Create activation script
cat > activate_venv.sh << EOF cat > "$SCRIPT_DIR/activate_venv.sh" << EOF
#!/bin/bash #!/bin/bash
SCRIPT_DIR="\$(cd "\$(dirname "\${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="\$(cd "\$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
# Activate Python virtual environment # ROS 2
source /opt/ros/${ROS_DISTRO}/setup.bash
# Gazebo
[ -f /usr/share/gazebo/setup.bash ] && source /usr/share/gazebo/setup.bash
[ -f /usr/share/gazebo-11/setup.bash ] && source /usr/share/gazebo-11/setup.bash
# Python venv
source "\$SCRIPT_DIR/venv/bin/activate" 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
# 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 # Gazebo paths
export GAZEBO_MODEL_PATH="\$SCRIPT_DIR/models:\$GAZEBO_MODEL_PATH" export GAZEBO_MODEL_PATH="\$SCRIPT_DIR/models:\$HOME/ardupilot_gazebo/models:\${GAZEBO_MODEL_PATH:-}"
export GAZEBO_RESOURCE_PATH="\$SCRIPT_DIR/worlds:\$GAZEBO_RESOURCE_PATH" export GAZEBO_RESOURCE_PATH="\$SCRIPT_DIR/worlds:\$HOME/ardupilot_gazebo/worlds:\${GAZEBO_RESOURCE_PATH:-}"
# ArduPilot Gazebo (if installed) # ArduPilot
if [ -d "\$HOME/ardupilot_gazebo" ]; then export PATH="\$PATH:\$HOME/ardupilot/Tools/autotest"
export GAZEBO_MODEL_PATH="\$HOME/ardupilot_gazebo/models:\$GAZEBO_MODEL_PATH" export ARDUPILOT_HOME="\$HOME/ardupilot"
export GAZEBO_RESOURCE_PATH="\$HOME/ardupilot_gazebo/worlds:\$GAZEBO_RESOURCE_PATH"
fi
# WSL environment (if applicable) # WSL
if [ -f "\$SCRIPT_DIR/wsl_env.sh" ]; then if grep -qEi "(microsoft|wsl)" /proc/version 2>/dev/null; then
source "\$SCRIPT_DIR/wsl_env.sh" [ -f "\$SCRIPT_DIR/wsl_env.sh" ] && source "\$SCRIPT_DIR/wsl_env.sh"
fi fi
echo -e "\033[0;32mEnvironment activated (ROS 2 ${ROS_DISTRO})\033[0m" 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 -e "${GREEN}==========================================${NC}" echo "Run simulation: bash scripts/run_simulation.sh"
echo -e "${GREEN} Setup Complete!${NC}" echo "With rendering: bash scripts/run_simulation.sh --software-render"
echo -e "${GREEN}==========================================${NC}" EOF
chmod +x "$SCRIPT_DIR/activate_venv.sh"
((STEP++))
# ============================================================================
# STEP 10: Make Scripts Executable
# ============================================================================
print_step $STEP "Finalizing installation"
chmod +x "$SCRIPT_DIR/scripts/"*.sh 2>/dev/null || true
chmod +x "$SCRIPT_DIR/activate_venv.sh" 2>/dev/null || true
((STEP++))
# ============================================================================
# COMPLETE
# ============================================================================
print_header "Installation Complete!"
echo -e "${GREEN}All components installed:${NC}"
echo " - ROS 2 $ROS_DISTRO"
echo " - Gazebo"
echo " - ArduPilot SITL ($ARDUPILOT_HOME)"
echo " - ardupilot_gazebo ($ARDUPILOT_GAZEBO_HOME)"
echo " - MAVROS"
echo " - Python dependencies"
echo "" echo ""
if $IS_WSL; then if $IS_WSL; then
echo -e "${YELLOW}WSL Setup Notes:${NC}" echo -e "${YELLOW}WSL Setup Notes:${NC}"
echo " - WSL environment file created: wsl_env.sh" echo " - GUI apps require WSLg (Windows 11) or VcXsrv (Windows 10)"
echo " - For GUI apps, ensure X server is running (Windows 11 has WSLg built-in)" echo " - Use --software-render flag if graphics are slow"
echo " - See docs/wsl_setup_guide.md for detailed instructions"
echo "" echo ""
fi fi
echo -e "${BLUE}Next steps:${NC}" echo -e "${CYAN}To run the simulation:${NC}"
echo " 1. source ~/.bashrc"
echo " 2. source activate_venv.sh"
echo " 3. bash scripts/run_simulation.sh"
echo "" echo ""
echo -e "${BLUE}GPS-Denied Navigation:${NC}" echo " cd $SCRIPT_DIR"
echo " - All navigation uses LOCAL coordinates" echo " source activate_venv.sh"
echo " - GPS is ONLY used for geofencing" echo " bash scripts/run_simulation.sh"
if $IS_WSL; then
echo "" echo ""
echo " # Or with software rendering for WSL:"
if ! check_ros2_installed && [ ! -f "/opt/ros/${ROS_DISTRO}/setup.bash" ]; then echo " bash scripts/run_simulation.sh --software-render"
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 fi
echo ""
echo -e "${GREEN}==========================================${NC}"

View File

@@ -15,6 +15,21 @@
<uri>model://ground_plane</uri> <uri>model://ground_plane</uri>
</include> </include>
<!-- UAV - Iris Quadcopter with Cameras -->
<include>
<uri>model://iris_with_camera</uri>
<name>uav</name>
<pose>0 0 0.1 0 0 0</pose>
</include>
<!-- UGV - Ground Vehicle -->
<include>
<uri>model://custom_ugv</uri>
<name>ugv</name>
<pose>2 2 0.1 0 0 0</pose>
</include>
<!-- Visual Markers for GPS-Denied Navigation -->
<model name="visual_markers"> <model name="visual_markers">
<static>true</static> <static>true</static>
<link name="marker_0"> <link name="marker_0">
@@ -55,6 +70,7 @@
</link> </link>
</model> </model>
<!-- Origin Marker (Yellow) -->
<model name="origin_marker"> <model name="origin_marker">
<static>true</static> <static>true</static>
<pose>0 0 0.01 0 0 0</pose> <pose>0 0 0.01 0 0 0</pose>
@@ -74,6 +90,7 @@
</link> </link>
</model> </model>
<!-- Spherical coordinates for geofencing reference -->
<spherical_coordinates> <spherical_coordinates>
<surface_model>EARTH_WGS84</surface_model> <surface_model>EARTH_WGS84</surface_model>
<latitude_deg>47.397742</latitude_deg> <latitude_deg>47.397742</latitude_deg>

106
worlds/iris_runway.world Normal file
View File

@@ -0,0 +1,106 @@
<?xml version="1.0" ?>
<sdf version="1.6">
<world name="iris_runway">
<physics type="ode">
<ode>
<solver>
<type>quick</type>
<iters>100</iters>
<sor>1.0</sor>
</solver>
<constraints>
<cfm>0.0</cfm>
<erp>0.9</erp>
<contact_max_correcting_vel>0.1</contact_max_correcting_vel>
<contact_surface_layer>0.0</contact_surface_layer>
</constraints>
</ode>
<max_step_size>0.001</max_step_size>
<real_time_factor>1.0</real_time_factor>
<real_time_update_rate>1000</real_time_update_rate>
</physics>
<include>
<uri>model://sun</uri>
</include>
<include>
<uri>model://ground_plane</uri>
</include>
<!-- ArduPilot Iris Quadcopter -->
<model name="iris">
<include>
<uri>model://iris_with_ardupilot</uri>
</include>
</model>
<!-- Visual Navigation Markers -->
<model name="marker_red">
<static>true</static>
<pose>10 0 0.01 0 0 0</pose>
<link name="link">
<visual name="visual">
<geometry><box><size>1 1 0.02</size></box></geometry>
<material>
<ambient>1 0 0 1</ambient>
<diffuse>1 0 0 1</diffuse>
</material>
</visual>
</link>
</model>
<model name="marker_green">
<static>true</static>
<pose>10 10 0.01 0 0 0</pose>
<link name="link">
<visual name="visual">
<geometry><box><size>1 1 0.02</size></box></geometry>
<material>
<ambient>0 1 0 1</ambient>
<diffuse>0 1 0 1</diffuse>
</material>
</visual>
</link>
</model>
<model name="marker_blue">
<static>true</static>
<pose>0 10 0.01 0 0 0</pose>
<link name="link">
<visual name="visual">
<geometry><box><size>1 1 0.02</size></box></geometry>
<material>
<ambient>0 0 1 1</ambient>
<diffuse>0 0 1 1</diffuse>
</material>
</visual>
</link>
</model>
<model name="origin_marker">
<static>true</static>
<pose>0 0 0.01 0 0 0</pose>
<link name="link">
<visual name="visual">
<geometry>
<cylinder><radius>0.5</radius><length>0.02</length></cylinder>
</geometry>
<material>
<ambient>1 1 0 1</ambient>
<diffuse>1 1 0 1</diffuse>
</material>
</visual>
</link>
</model>
<!-- Spherical coordinates for GPS geofencing -->
<spherical_coordinates>
<surface_model>EARTH_WGS84</surface_model>
<latitude_deg>-35.363262</latitude_deg>
<longitude_deg>149.165237</longitude_deg>
<elevation>584</elevation>
<heading_deg>0</heading_deg>
</spherical_coordinates>
</world>
</sdf>