Controller Update
This commit is contained in:
@@ -1,128 +1,211 @@
|
||||
# GPS-Denied Navigation
|
||||
|
||||
How the system navigates without GPS.
|
||||
## Overview
|
||||
|
||||
## Principle
|
||||
This system enables UAV/UGV navigation **without GPS** by using:
|
||||
|
||||
All navigation uses relative positioning from visual sensors. GPS is only used for geofencing (safety boundaries).
|
||||
1. **Visual Odometry** - Camera-based pose estimation
|
||||
2. **Optical Flow** - Velocity estimation from downward camera
|
||||
3. **IMU Integration** - Short-term dead reckoning
|
||||
4. **EKF Fusion** - Combine all sensors
|
||||
|
||||
| Function | GPS Used? |
|
||||
|----------|-----------|
|
||||
| Position estimation | No - visual odometry |
|
||||
| Waypoint navigation | No - local coordinates |
|
||||
| Velocity control | No - optical flow |
|
||||
| Geofencing | Yes - safety only |
|
||||
**GPS is ONLY used for geofencing (safety boundaries).**
|
||||
|
||||
## Position Estimation
|
||||
## How It Works
|
||||
|
||||
### Visual Odometry
|
||||
|
||||
1. Detect features in camera image (ORB, SIFT)
|
||||
2. Match features between consecutive frames
|
||||
3. Estimate camera motion from feature displacement
|
||||
4. Accumulate motion into position estimate
|
||||
```
|
||||
Frame N-1 Frame N
|
||||
│ │
|
||||
▼ ▼
|
||||
┌────────┐ ┌────────┐
|
||||
│Features│──│Features│ → Match features
|
||||
└────────┘ └────────┘
|
||||
│ │
|
||||
└─────┬─────┘
|
||||
▼
|
||||
Essential Matrix → Rotation + Translation
|
||||
```
|
||||
|
||||
**Algorithm:**
|
||||
1. Detect ORB/SIFT features in current frame
|
||||
2. Match with previous frame features
|
||||
3. Compute Essential Matrix (RANSAC)
|
||||
4. Recover rotation and translation
|
||||
5. Integrate to get absolute pose
|
||||
|
||||
### Optical Flow
|
||||
|
||||
1. Capture ground images from downward camera
|
||||
2. Measure pixel displacement between frames
|
||||
3. Convert to velocity using altitude
|
||||
4. Integrate for position
|
||||
```
|
||||
Downward Camera
|
||||
│
|
||||
▼
|
||||
┌───────┐
|
||||
│ Image │ → Lucas-Kanade flow
|
||||
└───────┘
|
||||
│
|
||||
▼
|
||||
Pixel velocity × Altitude / Focal length = Ground velocity
|
||||
```
|
||||
|
||||
**Works best at:**
|
||||
- Altitudes 0.5m - 10m
|
||||
- Textured ground surfaces
|
||||
- Stable lighting
|
||||
|
||||
### Sensor Fusion
|
||||
|
||||
Extended Kalman Filter combines:
|
||||
- Visual odometry (position)
|
||||
- Optical flow (velocity)
|
||||
- IMU (acceleration, rotation)
|
||||
- Barometer (altitude)
|
||||
```
|
||||
Visual Odometry ─┬─→ Weighted Average ─→ Position Estimate
|
||||
Optical Flow ────┤
|
||||
IMU ─────────────┘
|
||||
```
|
||||
|
||||
Output: Full 6-DOF pose estimate
|
||||
**Weights (configurable):**
|
||||
- Visual Odometry: 60%
|
||||
- Optical Flow: 30%
|
||||
- IMU: 10%
|
||||
|
||||
## ArduPilot Configuration
|
||||
|
||||
Key parameters for GPS-denied operation:
|
||||
### EKF3 External Navigation
|
||||
|
||||
```
|
||||
# EKF Source Configuration
|
||||
EK3_SRC1_POSXY = 6 # External Nav for position
|
||||
EK3_SRC1_VELXY = 6 # External Nav for velocity
|
||||
EK3_SRC1_POSZ = 1 # Barometer for altitude
|
||||
# GPS Type - Disabled
|
||||
GPS_TYPE 0
|
||||
GPS_TYPE2 0
|
||||
|
||||
# Disable GPS for navigation
|
||||
GPS_TYPE = 0 # No GPS (or keep for geofence)
|
||||
# EKF3 Source Configuration
|
||||
AHRS_EKF_TYPE 3 # Use EKF3
|
||||
EK3_ENABLE 1
|
||||
EK2_ENABLE 0
|
||||
|
||||
# Enable external navigation
|
||||
VISO_TYPE = 1 # Enable visual odometry input
|
||||
# Position from External Nav
|
||||
EK3_SRC1_POSXY 6 # External Nav
|
||||
EK3_SRC1_POSZ 1 # Barometer
|
||||
EK3_SRC1_VELXY 6 # External Nav
|
||||
EK3_SRC1_VELZ 0 # None
|
||||
EK3_SRC1_YAW 6 # External Nav
|
||||
|
||||
# Arming checks
|
||||
ARMING_CHECK = 0 # Disable pre-arm checks (for testing)
|
||||
# Vision Position Input
|
||||
VISO_TYPE 1 # MAVLink
|
||||
VISO_POS_X 0.1 # Camera offset
|
||||
VISO_DELAY_MS 50 # Processing delay
|
||||
```
|
||||
|
||||
See `config/ardupilot_gps_denied.parm` for complete parameters.
|
||||
### Arming Checks
|
||||
|
||||
## Sending Position to ArduPilot
|
||||
```
|
||||
# For simulation, disable all
|
||||
ARMING_CHECK 0
|
||||
|
||||
Visual odometry sends position via MAVLink:
|
||||
# For real flight, keep safety checks
|
||||
# ARMING_CHECK 14 # Skip GPS only
|
||||
```
|
||||
|
||||
## Coordinate Frames
|
||||
|
||||
### Local NED Frame
|
||||
|
||||
```
|
||||
North (X+)
|
||||
↑
|
||||
│
|
||||
│
|
||||
West ←─────┼─────→ East (Y+)
|
||||
│
|
||||
│
|
||||
↓
|
||||
(Down is Z+)
|
||||
```
|
||||
|
||||
**All navigation uses LOCAL coordinates:**
|
||||
- Takeoff point is origin (0, 0, 0)
|
||||
- No global GPS coordinates
|
||||
- Relative waypoints only
|
||||
|
||||
### Example Waypoints
|
||||
|
||||
```python
|
||||
# VISION_POSITION_ESTIMATE message
|
||||
msg = mavutil.mavlink.MAVLink_vision_position_estimate_message(
|
||||
usec=timestamp_us,
|
||||
x=position_x, # meters, NED frame
|
||||
y=position_y,
|
||||
z=position_z,
|
||||
roll=roll, # radians
|
||||
pitch=pitch,
|
||||
yaw=yaw
|
||||
)
|
||||
```
|
||||
|
||||
## Drift Mitigation
|
||||
|
||||
Visual odometry accumulates drift over time. Strategies:
|
||||
|
||||
1. **Loop Closure**: Recognize previously visited locations
|
||||
2. **Landmark Matching**: Use known visual markers
|
||||
3. **Multi-Sensor Fusion**: Weight sensors by confidence
|
||||
4. **Periodic Reset**: Return to known position
|
||||
|
||||
## Geofencing
|
||||
|
||||
GPS is only used for safety boundaries:
|
||||
|
||||
```yaml
|
||||
geofence:
|
||||
enabled: true
|
||||
use_gps: true
|
||||
fence_type: polygon
|
||||
action: RTL
|
||||
max_altitude: 50
|
||||
```
|
||||
|
||||
If drone crosses boundary, triggers return-to-launch.
|
||||
|
||||
## Coordinate System
|
||||
|
||||
All waypoints use local NED coordinates:
|
||||
- X: North (meters from origin)
|
||||
- Y: East (meters from origin)
|
||||
- Z: Down (negative for altitude)
|
||||
|
||||
Example mission:
|
||||
```python
|
||||
# Square pattern (5m sides)
|
||||
waypoints = [
|
||||
{"x": 0, "y": 0, "z": -5}, # Takeoff to 5m
|
||||
{"x": 10, "y": 0, "z": -5}, # 10m north
|
||||
{"x": 10, "y": 10, "z": -5}, # 10m east
|
||||
{"x": 0, "y": 0, "z": -5}, # Return
|
||||
{"x": 0, "y": 0, "z": 0}, # Land
|
||||
(5, 0, -5), # North 5m, altitude 5m
|
||||
(5, 5, -5), # North-East corner
|
||||
(0, 5, -5), # East
|
||||
(0, 0, -5), # Back to start
|
||||
]
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
- Drift accumulates over distance/time
|
||||
- Requires visual features (fails in featureless environments)
|
||||
- Requires sufficient lighting
|
||||
- Performance degrades with fast motion or blur
|
||||
### Visual Odometry
|
||||
- **Scale drift**: Position error grows over time
|
||||
- **Texture needed**: Poor in featureless environments
|
||||
- **Lighting**: Affected by shadows, brightness changes
|
||||
- **Motion blur**: High-speed motion degrades accuracy
|
||||
|
||||
### Optical Flow
|
||||
- **Altitude dependent**: Accuracy varies with height
|
||||
- **Ground texture**: Needs visible ground features
|
||||
- **Tilt sensitivity**: Assumes mostly horizontal flight
|
||||
|
||||
### Mitigation Strategies
|
||||
|
||||
1. **Loop closure**: Return to known positions
|
||||
2. **Landmark detection**: ArUco markers for correction
|
||||
3. **Multi-sensor fusion**: Combine VO + OF + IMU
|
||||
4. **Flight patterns**: Minimize cumulative drift
|
||||
|
||||
## Geofencing (GPS Only)
|
||||
|
||||
GPS is used **only** for safety:
|
||||
|
||||
```python
|
||||
# Geofence uses GPS coordinates
|
||||
fence_points = [
|
||||
(47.397742, 8.545594), # Corner 1 (lat, lon)
|
||||
(47.398242, 8.545594), # Corner 2
|
||||
(47.398242, 8.546094), # Corner 3
|
||||
(47.397742, 8.546094), # Corner 4
|
||||
]
|
||||
|
||||
# But navigation uses local coordinates
|
||||
current_position = (10.5, 3.2, -5.0) # NED, meters
|
||||
```
|
||||
|
||||
**Breach Actions:**
|
||||
- `RTL` - Return to local origin
|
||||
- `LAND` - Land immediately
|
||||
- `HOLD` - Hold position
|
||||
|
||||
## Testing GPS-Denied Mode
|
||||
|
||||
### 1. Verify EKF Source
|
||||
|
||||
In MAVProxy:
|
||||
```
|
||||
param show EK3_SRC*
|
||||
```
|
||||
|
||||
Should show:
|
||||
```
|
||||
EK3_SRC1_POSXY 6.0
|
||||
EK3_SRC1_VELXY 6.0
|
||||
```
|
||||
|
||||
### 2. Check Vision Input
|
||||
|
||||
```bash
|
||||
ros2 topic echo /uav/visual_odometry/pose
|
||||
```
|
||||
|
||||
Should show updating position.
|
||||
|
||||
### 3. Monitor EKF Status
|
||||
|
||||
```bash
|
||||
ros2 topic echo /uav/mavros/state
|
||||
```
|
||||
|
||||
Should show `connected: true` and `mode: GUIDED`.
|
||||
|
||||
Reference in New Issue
Block a user