docs: Improve quick start, ArduPilot setup, and troubleshooting, and add GPS mode option.

This commit is contained in:
2026-01-07 21:27:34 +00:00
parent 202465af99
commit 3251fc7b27
6 changed files with 350 additions and 294 deletions

View File

@@ -1,42 +1,39 @@
# ArduPilot + Gazebo Guide
## Overview
This project uses:
- **ArduPilot SITL**: Software-in-the-loop flight controller
- **Gazebo**: 3D physics simulation
- **MAVLink**: Communication protocol
## Architecture
```
┌─────────────┐ JSON (UDP 9002) ┌─────────────┐ MAVLink (TCP 5760) ┌─────────────┐
Gazebo │◄──────────────────────►│ ArduPilot │◄────────────────────────►│ Your
(Physics) │ sensor data │ SITL │ commands/telemetry Controller │
└─────────────┘ └─────────────┘ └─────────────┘
┌───────────────── UDP 9002 ┌──────────────── TCP 5760 ┌─────────────────
│ JSON sensor data │ │ MAVLink cmds │
Gazebo │◄─────────────────────►│ ArduPilot SITL │◄───────────────────►│ Controller
│ (Physics) motor commands (ArduCopter) telemetry │ (run_ardupilot) │
│ │ │ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
```
## Quick Start
## Quick Start (3 Terminals)
### Step 1: Start Gazebo
### Terminal 1: Start Gazebo FIRST
```bash
cd ~/RDC_Simulation
./scripts/run_ardupilot_sim.sh runway
```
Wait until the drone appears in the 3D view.
Wait until the drone appears in the 3D view!
### Step 2: Start SITL
### Terminal 2: Start ArduCopter SITL
```bash
source ~/venv-ardupilot/bin/activate
sim_vehicle.py -v ArduCopter -f gazebo-iris --model JSON --console
```
You should see telemetry scrolling (NOT "No JSON sensor message").
You should see:
- "JSON received: timestamp, imu, position..." ✅
- NOT "No JSON sensor message received" ❌
### Step 3: Run Controller
### Terminal 3: Run Controller
```bash
source ~/venv-ardupilot/bin/activate
@@ -53,44 +50,72 @@ python scripts/run_ardupilot.py --pattern square --size 5 --altitude 5
# Circle pattern (5m radius)
python scripts/run_ardupilot.py --pattern circle --size 5
# Hover in place for testing
# Hover in place
python scripts/run_ardupilot.py --pattern hover
# Larger pattern at higher altitude
python scripts/run_ardupilot.py --pattern square --size 10 --altitude 15
# GPS mode (instead of GPS-denied)
python scripts/run_ardupilot.py --pattern square --gps
```
## Controller Code
The flight controller is in `src/drone_controller.py`:
```python
from src.drone_controller import DroneController
drone = DroneController()
drone.connect()
drone.set_mode("GUIDED")
# GPS-denied setup
drone.setup_gps_denied()
drone.set_mode("GUIDED_NOGPS")
# Or GPS mode
# drone.set_mode("GUIDED")
drone.arm()
drone.takeoff(5.0)
drone.fly_square(size=5, altitude=5)
drone.land()
```
### Key Methods
## ArduCopter Flight Modes
| Method | Description |
|--------|-------------|
| `connect()` | Connect to SITL via MAVLink |
| `set_mode(mode)` | Set flight mode (GUIDED, LAND, etc.) |
| `arm()` | Arm motors (force arm) |
| `takeoff(alt)` | Take off to altitude |
| `goto(x, y, z)` | Go to position (NED frame) |
| `fly_to_and_wait(x, y, alt)` | Go to position and wait |
| `fly_square(size, alt)` | Fly square pattern |
| `fly_circle(radius, alt)` | Fly circle pattern |
| `land()` | Land the drone |
| Mode | ID | Description |
|------|-----|-------------|
| STABILIZE | 0 | Manual, self-leveling |
| ALT_HOLD | 2 | Hold altitude |
| GUIDED | 4 | Waypoint commands (GPS required) |
| LOITER | 5 | Hold position (GPS required) |
| RTL | 6 | Return to launch |
| LAND | 9 | Automatic landing |
| **GUIDED_NOGPS** | 20 | Commands without GPS |
## Available Worlds
## MAVProxy Commands
In the SITL console, you can type:
```bash
# Check status
status
# Change mode
mode GUIDED
mode GUIDED_NOGPS
# Arm
arm throttle force
# Takeoff (in GUIDED mode)
takeoff 5
# Land
mode LAND
# Set parameter
param set ARMING_CHECK 0
```
## Gazebo Worlds
```bash
# Outdoor runway (default)
@@ -102,83 +127,73 @@ drone.land()
## MAVLink Connection
The controller connects via TCP port 5760:
Default: `tcp:127.0.0.1:5760`
```python
# config.py
MAVLINK = {
"connection_string": "tcp:127.0.0.1:5760",
}
```
Port map:
- **5760**: Primary MAVLink (SERIAL0)
- **5762**: Secondary (SERIAL1)
- **5763**: Tertiary (SERIAL2)
- **14550**: MAVProxy GCS output (UDP)
## Troubleshooting
### "No JSON sensor message received"
SITL isn't receiving data from Gazebo.
Gazebo isn't sending data.
**Fix:**
1. Make sure Gazebo is running FIRST
2. Wait for the world to fully load
2. Wait for world to fully load
3. Then start SITL
### Drone won't arm
**Fix:**
```bash
# Check pre-arm status in MAVProxy
arm status
# Force arm
# In MAVProxy console
arm throttle force
# Or set in your code
drone.set_param("ARMING_CHECK", 0)
```
### Wrong Python environment
### Wrong vehicle type (ArduPlane)
Mode list shows FBWA, FBWB, QSTABILIZE instead of GUIDED_NOGPS, ALT_HOLD.
**Fix:**
```bash
source ~/venv-ardupilot/bin/activate
which python3 # Should be ~/venv-ardupilot/bin/python3
pkill -9 -f sim_vehicle
sim_vehicle.py -v ArduCopter -f gazebo-iris --model JSON --console --wipe-eeprom
```
### Mode not changing
The controller hardcodes mode IDs for ArduCopter. If using ArduPlane, modes will differ.
### Gazebo plugin not loading
**Fix:**
```bash
# Check plugin exists
ls ~/ardupilot_gazebo/build/libArduPilotPlugin.so
# Check paths
# Check environment
echo $GZ_SIM_SYSTEM_PLUGIN_PATH
# Should include: ~/ardupilot_gazebo/build
```
## Manual SITL Control
Use MAVProxy commands:
```bash
# In SITL console
mode GUIDED
arm throttle force
takeoff 5
# Move to position
guided 10 0 -5
# Land
mode LAND
```
## Useful Commands
## Useful Debug Commands
```bash
# List Gazebo topics
gz topic -l
# Check SITL status
sim_vehicle.py -v ArduCopter -f gazebo-iris --model JSON --console --map
# Echo a topic
gz topic -e -t /model/iris_with_gimbal/pose
# View camera (if available)
gz topic -e -t /camera
# Check SITL processes
ps aux | grep ardupilot
# Check port usage
lsof -i :5760
```

View File

@@ -2,43 +2,45 @@
## Overview
The drone controller (`src/drone_controller.py`) provides a simple interface for flying the drone in simulation.
The `DroneController` class (`src/drone_controller.py`) provides a simple interface for controlling the drone in ArduPilot SITL simulation.
## Usage
### Command Line
## Command Line Usage
```bash
# Activate environment first
source ~/venv-ardupilot/bin/activate
cd ~/RDC_Simulation
# Fly a square pattern
# Run flight patterns
python scripts/run_ardupilot.py --pattern square
# Options
python scripts/run_ardupilot.py --help
python scripts/run_ardupilot.py --pattern circle
python scripts/run_ardupilot.py --pattern hover
```
### Options
| Option | Default | Description |
|--------|---------|-------------|
| `--pattern` | square | Flight pattern: square, circle, hover |
| `--altitude` | 5 | Flight altitude in meters |
| `--size` | 5 | Pattern size (side length or radius) |
| `--connection` | tcp:127.0.0.1:5760 | MAVLink connection string |
| `--pattern, -p` | square | Flight pattern: square, circle, hover |
| `--altitude, -a` | 5.0 | Flight altitude in meters |
| `--size, -s` | 5.0 | Pattern size (side length or radius) |
| `--connection, -c` | tcp:127.0.0.1:5760 | MAVLink connection string |
| `--gps` | false | Use GPS mode (default is GPS-denied) |
### Examples
```bash
# Fly a 10m square at 8m altitude
python scripts/run_ardupilot.py --pattern square --size 10 --altitude 8
# Large square at high altitude
python scripts/run_ardupilot.py --pattern square --size 10 --altitude 15
# Fly a circle with 5m radius
python scripts/run_ardupilot.py --pattern circle --size 5
# Small circle
python scripts/run_ardupilot.py --pattern circle --size 3 --altitude 5
# Just hover (useful for testing)
# Hover for testing
python scripts/run_ardupilot.py --pattern hover
# GPS mode (instead of GPS-denied)
python scripts/run_ardupilot.py --pattern square --gps
```
## Python API
@@ -54,123 +56,119 @@ if not drone.connect():
print("Connection failed")
exit(1)
# Takeoff
drone.set_mode("GUIDED")
# Setup for GPS-denied (disables arming checks)
drone.setup_gps_denied()
# Set mode and arm
drone.set_mode("GUIDED_NOGPS") # or "GUIDED" for GPS mode
drone.arm()
# Takeoff
drone.takeoff(5.0)
# Fly
# Fly a pattern
drone.fly_square(size=5, altitude=5)
# Land
drone.land()
```
### Class: DroneController
### DroneController Class
#### Connection
#### Constructor
```python
drone = DroneController(connection_string="tcp:127.0.0.1:5760")
drone.connect(timeout=30) # Returns True/False
```
#### State
#### Properties
```python
drone.armed # bool: Is the drone armed?
drone.mode # str: Current flight mode
drone.altitude # float: Current altitude (m)
drone.position # dict: {"x": float, "y": float, "z": float}
```
| Property | Type | Description |
|----------|------|-------------|
| `armed` | bool | Is the drone armed? |
| `mode` | str | Current flight mode |
| `altitude` | float | Current altitude (meters) |
| `position` | dict | Current position {"x", "y", "z"} |
| `vehicle_type` | str | "copter" or "plane" |
#### Commands
#### Methods
```python
drone.set_mode("GUIDED") # Set flight mode
drone.arm() # Arm motors (force arm)
drone.takeoff(5.0) # Takeoff to altitude
drone.goto(x, y, z) # Go to position (NED frame)
drone.fly_to_and_wait(x, y, alt) # Go and wait until reached
drone.land() # Land
```
| Method | Description |
|--------|-------------|
| `connect(timeout=30)` | Connect to SITL, returns True/False |
| `set_mode(mode)` | Set flight mode (GUIDED, GUIDED_NOGPS, LAND, etc.) |
| `setup_gps_denied()` | Configure for GPS-denied operation |
| `arm()` | Arm motors (force arm) |
| `takeoff(altitude)` | Take off to altitude |
| `goto(x, y, z)` | Go to position (NED frame) |
| `fly_to_and_wait(x, y, alt)` | Go to position and wait until reached |
| `fly_square(size, alt)` | Fly square pattern |
| `fly_circle(radius, alt)` | Fly circle pattern |
| `land()` | Land the drone |
| `set_param(name, value)` | Set an ArduPilot parameter |
#### Patterns
### Flight Modes (ArduCopter)
```python
drone.fly_square(size=5, altitude=5) # Square pattern
drone.fly_circle(radius=5, altitude=5) # Circle pattern
```
| Mode | ID | Description |
|------|-----|-------------|
| STABILIZE | 0 | Manual control, self-leveling |
| ALT_HOLD | 2 | Hold altitude, manual position |
| GUIDED | 4 | Accept waypoint commands (needs GPS) |
| LOITER | 5 | Hold position |
| RTL | 6 | Return to launch |
| LAND | 9 | Automatic landing |
| GUIDED_NOGPS | 20 | Accept commands without GPS |
## Coordinate System
ArduPilot uses NED (North-East-Down):
- **X**: North (positive forward)
- **Y**: East (positive right)
- **Z**: Down (negative is up!)
- **X (North)**: Positive = forward
- **Y (East)**: Positive = right
- **Z (Down)**: Positive = down, **negative = up!**
```python
# Go 5m north, 3m east, at 10m altitude
drone.goto(5, 3, -10) # Z is negative for altitude
# Go 5m forward, 3m right, at 10m altitude
drone.goto(5, 3, -10) # Z is negative for altitude!
```
## Flight Modes
## GPS-Denied Mode
| Mode | Description |
|------|-------------|
| GUIDED | Accept external commands |
| LAND | Automatic landing |
| LOITER | Hold position |
| RTL | Return to launch |
| STABILIZE | Manual control |
The controller defaults to GPS-denied mode, which:
## Sequence Diagram
1. Disables arming checks (`ARMING_CHECK=0`)
2. Uses `GUIDED_NOGPS` mode (ID 20)
3. Relies on barometer for altitude
```
┌─────────┐ ┌──────────┐ ┌─────────┐
│ Gazebo │ │ SITL │ │ Script │
└────┬────┘ └────┬─────┘ └────┬────┘
│ │ │
│ Physics data │ │
│ ◄──────────────│ │
│ │ │
│ Sensor JSON │ │
│ ───────────────► │
│ │ Connect │
│ │ ◄────────────────│
│ │ │
│ │ Set GUIDED │
│ │ ◄────────────────│
│ │ │
│ │ Arm │
│ │ ◄────────────────│
│ │ │
│ │ Takeoff │
│ │ ◄────────────────│
│ │ │
│ Motor commands │ │
│ ◄──────────────│ │
│ │ │
│ Drone moves │ │
│ │ │
To use GPS mode instead:
```bash
python scripts/run_ardupilot.py --pattern square --gps
```
## Troubleshooting
### Drone doesn't move
### Drone won't arm
1. Check Gazebo is running
2. Check SITL shows telemetry (not "No JSON sensor message")
3. Check drone is armed
1. Check MAVProxy console for pre-arm errors
2. Try force arming in MAVProxy: `arm throttle force`
3. Make sure SITL is connected to Gazebo (shows "JSON received:")
### Timeout waiting for altitude
### Mode not changing
- Increase takeoff timeout
- Check for pre-arm failures in SITL console
### Connection refused
```bash
# Check SITL is running
nc -z 127.0.0.1 5760 && echo "SITL is ready" || echo "SITL not running"
Check the current mode in MAVProxy console. If stuck, try:
```
mode GUIDED
```
### Drone not moving
1. Make sure you're in GUIDED or GUIDED_NOGPS mode
2. Check altitude - drone needs to be off ground
3. Verify Gazebo is running and responsive
### Wrong vehicle type detected
If you see ArduPlane modes (FBWA, FBWB), restart SITL:
```bash
pkill -9 -f sim_vehicle
sim_vehicle.py -v ArduCopter -f gazebo-iris --model JSON --console --wipe-eeprom
```

View File

@@ -2,19 +2,23 @@
## System Requirements
- **OS**: Ubuntu 22.04 or 24.04 (Windows users: use WSL2)
- **RAM**: 8GB minimum, 16GB recommended
- **Disk**: 10GB free space
- **GPU**: Any GPU with OpenGL 3.3+ support
| Requirement | Minimum | Recommended |
|-------------|---------|-------------|
| **OS** | Ubuntu 22.04 | Ubuntu 24.04 |
| **RAM** | 8 GB | 16 GB |
| **Disk** | 10 GB | 20 GB |
| **GPU** | OpenGL 3.3 | NVIDIA/AMD dedicated |
## Quick Install (Ubuntu)
> **Windows users**: Use WSL2 with Ubuntu (see below)
## Quick Install (Ubuntu/WSL2)
```bash
# Clone repository
git clone <repo-url> RDC_Simulation
cd RDC_Simulation
git clone <repo-url> ~/RDC_Simulation
cd ~/RDC_Simulation
# Run installer (includes ArduPilot)
# Run full installer (includes ArduPilot)
./setup/install_ubuntu.sh --with-ardupilot
# Reload shell
@@ -22,11 +26,11 @@ source ~/.bashrc
```
This installs:
- Python 3 + virtual environment
- Gazebo Harmonic
- ArduPilot SITL
- ArduPilot Gazebo plugin
- MAVProxy
- Python 3 + virtual environment
- Gazebo Harmonic
- ArduPilot SITL
- ArduPilot Gazebo plugin
- MAVProxy
## Windows (WSL2)
@@ -36,7 +40,8 @@ Open PowerShell as Administrator:
```powershell
wsl --install -d Ubuntu-24.04
```
Restart computer, then open Ubuntu from Start menu.
Restart your computer, then open "Ubuntu" from the Start menu.
### Step 2: Install in WSL
@@ -49,32 +54,20 @@ git clone <repo-url> ~/RDC_Simulation
cd ~/RDC_Simulation
./setup/install_ubuntu.sh --with-ardupilot
# Reload
# Reload shell
source ~/.bashrc
```
### WSL2 Tips
- **GUI Apps**: Windows 11 has WSLg built-in. Gazebo should work automatically.
- **GPU**: Install NVIDIA WSL driver from [nvidia.com/wsl](https://developer.nvidia.com/cuda/wsl)
- **Access Windows files**: `/mnt/c/Users/YourName/`
- **Performance**: Clone repo to Linux filesystem (not `/mnt/c/`)
## macOS
macOS doesn't support Gazebo Harmonic natively. Options:
1. **Docker** (recommended): Use Linux container
2. **VM**: Use UTM or Parallels with Ubuntu
3. **Standalone**: Run PyBullet-only simulation
```bash
# Install basic dependencies
./setup/install_macos.sh
# Use standalone simulation
python standalone_simulation.py
```
- **GUI**: Windows 11 has WSLg built-in. Gazebo should work automatically.
- **GPU**: Install [NVIDIA WSL driver](https://developer.nvidia.com/cuda/wsl) for GPU acceleration
- **Performance**: Keep files in Linux filesystem (`~/`), not Windows (`/mnt/c/`)
- **Memory**: WSL may need more RAM. Create `~/.wslconfig` in Windows:
```ini
[wsl2]
memory=8GB
```
## Arch Linux
@@ -83,46 +76,51 @@ python standalone_simulation.py
source ~/.bashrc
```
## macOS
macOS doesn't support Gazebo Harmonic. Options:
1. **Docker**: Run Linux in container
2. **VM**: Use UTM/Parallels with Ubuntu
3. **Basic**: PyBullet-only simulation
```bash
./setup/install_macos.sh
```
## Verify Installation
```bash
# Check ArduPilot
# Check ArduPilot virtual environment
source ~/venv-ardupilot/bin/activate
python -c "import em; print('empy OK')"
sim_vehicle.py --help
python -c "import em; print('empy: OK')"
which sim_vehicle.py
# Check Gazebo
gz sim --version
# Check ArduPilot plugin
ls ~/ardupilot_gazebo/build/libArduPilotPlugin.so
```
## Post-Installation
### Environment Setup
The installer creates `activate.sh` in the project root:
## First Run
### Terminal 1 - Gazebo
```bash
cd ~/RDC_Simulation
source activate.sh
```
This sources:
- ROS 2 (if installed)
- ArduPilot virtual environment
- Gazebo paths
### First Run
```bash
# Terminal 1: Start Gazebo
./scripts/run_ardupilot_sim.sh runway
```
Wait for the drone to appear!
# Terminal 2: Start SITL (after Gazebo loads)
### Terminal 2 - SITL
```bash
source ~/venv-ardupilot/bin/activate
sim_vehicle.py -v ArduCopter -f gazebo-iris --model JSON --console
```
Wait for "JSON received:" messages.
# Terminal 3: Run controller
### Terminal 3 - Controller
```bash
source ~/venv-ardupilot/bin/activate
cd ~/RDC_Simulation
python scripts/run_ardupilot.py --pattern square
@@ -137,30 +135,29 @@ source ~/venv-ardupilot/bin/activate
pip install empy==3.3.4
```
### "No JSON sensor message"
SITL isn't receiving data from Gazebo.
- Start Gazebo FIRST
- Wait for it to fully load
- Then start SITL
### "sim_vehicle.py not found"
```bash
source ~/.ardupilot_env
# OR
# Or add to PATH manually:
export PATH=$PATH:~/ardupilot/Tools/autotest
```
### Gazebo crashes / slow
### "No JSON sensor message"
SITL isn't receiving data from Gazebo.
- Start Gazebo FIRST
- Wait for world to fully load
- Then start SITL
### Gazebo crashes or slow
```bash
# Check GPU
glxinfo | grep "OpenGL renderer"
# Try software rendering (slow but works)
# Force software rendering (slow but works)
export LIBGL_ALWAYS_SOFTWARE=1
gz sim -v4 -r ~/ardupilot_gazebo/worlds/iris_runway.sdf
```
### WSL: Display not working
@@ -169,6 +166,14 @@ gz sim -v4 -r ~/ardupilot_gazebo/worlds/iris_runway.sdf
# Check WSLg
ls /mnt/wslg
# If missing, update WSL
# Update WSL if missing
wsl --update
```
### ArduPlane instead of ArduCopter
If mode list shows FBWA, FBWB (plane modes):
```bash
pkill -9 -f sim_vehicle
sim_vehicle.py -v ArduCopter -f gazebo-iris --model JSON --console --wipe-eeprom
```