Initial Attempt
This commit is contained in:
184
docs/protocol.md
Normal file
184
docs/protocol.md
Normal file
@@ -0,0 +1,184 @@
|
||||
# Communication Protocol (GPS-Denied)
|
||||
|
||||
Message formats for GPS-denied drone operation with camera.
|
||||
|
||||
## Drone Commands
|
||||
|
||||
```json
|
||||
{
|
||||
"thrust": 0.5,
|
||||
"pitch": 0.1,
|
||||
"roll": -0.2,
|
||||
"yaw": 0.0
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Range | Description |
|
||||
|-------|-------|-------------|
|
||||
| `thrust` | ±1.0 | Vertical thrust (positive = up) |
|
||||
| `pitch` | ±0.5 | Forward/backward tilt |
|
||||
| `roll` | ±0.5 | Left/right tilt |
|
||||
| `yaw` | ±0.5 | Rotation |
|
||||
|
||||
---
|
||||
|
||||
## Drone Telemetry
|
||||
|
||||
Published on `/drone/telemetry`. **No GPS position available.**
|
||||
|
||||
```json
|
||||
{
|
||||
"imu": {
|
||||
"orientation": {"roll": 0.0, "pitch": 0.0, "yaw": 0.0},
|
||||
"angular_velocity": {"x": 0.0, "y": 0.0, "z": 0.0},
|
||||
"linear_acceleration": {"x": 0.0, "y": 0.0, "z": 9.81}
|
||||
},
|
||||
"altimeter": {
|
||||
"altitude": 5.0,
|
||||
"vertical_velocity": -0.1
|
||||
},
|
||||
"velocity": {"x": 0.0, "y": 0.0, "z": -0.1},
|
||||
"landing_pad": {
|
||||
"relative_x": 0.5,
|
||||
"relative_y": -0.2,
|
||||
"distance": 4.5,
|
||||
"confidence": 0.85
|
||||
},
|
||||
"camera": {
|
||||
"width": 320,
|
||||
"height": 240,
|
||||
"fov": 60.0,
|
||||
"image": "<base64 encoded JPEG>"
|
||||
},
|
||||
"landed": false,
|
||||
"timestamp": 1.234
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sensor Details
|
||||
|
||||
### IMU
|
||||
Always available.
|
||||
|
||||
| Field | Unit | Description |
|
||||
|-------|------|-------------|
|
||||
| `orientation.roll/pitch/yaw` | radians | Euler angles |
|
||||
| `angular_velocity.x/y/z` | rad/s | Rotation rates |
|
||||
| `linear_acceleration.x/y/z` | m/s² | Acceleration |
|
||||
|
||||
### Altimeter
|
||||
Always available.
|
||||
|
||||
| Field | Unit | Description |
|
||||
|-------|------|-------------|
|
||||
| `altitude` | meters | Height above ground |
|
||||
| `vertical_velocity` | m/s | Vertical speed |
|
||||
|
||||
### Velocity
|
||||
Estimated from optical flow.
|
||||
|
||||
| Field | Unit | Description |
|
||||
|-------|------|-------------|
|
||||
| `x` | m/s | Forward velocity |
|
||||
| `y` | m/s | Lateral velocity |
|
||||
| `z` | m/s | Vertical velocity |
|
||||
|
||||
### Landing Pad Detection
|
||||
**May be null if pad not visible!**
|
||||
|
||||
| Field | Unit | Description |
|
||||
|-------|------|-------------|
|
||||
| `relative_x` | meters | Forward/back offset (body frame) |
|
||||
| `relative_y` | meters | Left/right offset (body frame) |
|
||||
| `distance` | meters | Vertical distance to pad |
|
||||
| `confidence` | 0-1 | Detection confidence |
|
||||
|
||||
### Camera
|
||||
Always available.
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `width` | Image width in pixels |
|
||||
| `height` | Image height in pixels |
|
||||
| `fov` | Horizontal field of view in degrees |
|
||||
| `image` | Base64 encoded JPEG (or null) |
|
||||
|
||||
---
|
||||
|
||||
## Using the Camera Image
|
||||
|
||||
The camera provides a base64-encoded JPEG image of what the drone sees looking down.
|
||||
|
||||
### Decoding the Image (Python)
|
||||
|
||||
```python
|
||||
import base64
|
||||
from PIL import Image
|
||||
import io
|
||||
|
||||
def decode_camera_image(telemetry):
|
||||
camera = telemetry.get('camera', {})
|
||||
image_b64 = camera.get('image')
|
||||
|
||||
if image_b64 is None:
|
||||
return None
|
||||
|
||||
# Decode base64 to bytes
|
||||
image_bytes = base64.b64decode(image_b64)
|
||||
|
||||
# Load as PIL Image
|
||||
image = Image.open(io.BytesIO(image_bytes))
|
||||
|
||||
return image
|
||||
```
|
||||
|
||||
### Using with OpenCV
|
||||
|
||||
```python
|
||||
import base64
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
def decode_camera_image_cv2(telemetry):
|
||||
camera = telemetry.get('camera', {})
|
||||
image_b64 = camera.get('image')
|
||||
|
||||
if image_b64 is None:
|
||||
return None
|
||||
|
||||
# Decode base64 to bytes
|
||||
image_bytes = base64.b64decode(image_b64)
|
||||
|
||||
# Convert to numpy array
|
||||
nparr = np.frombuffer(image_bytes, np.uint8)
|
||||
|
||||
# Decode JPEG
|
||||
image = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
|
||||
|
||||
return image
|
||||
```
|
||||
|
||||
### Image Properties
|
||||
|
||||
- **Resolution**: 320 x 240 pixels
|
||||
- **Format**: JPEG (quality 70)
|
||||
- **FOV**: 60 degrees
|
||||
- **Direction**: Downward-facing
|
||||
- **Update Rate**: ~5 Hz (every 5th telemetry frame)
|
||||
|
||||
---
|
||||
|
||||
## Rover Telemetry
|
||||
|
||||
For internal use by RoverController.
|
||||
|
||||
```json
|
||||
{
|
||||
"position": {"x": 1.5, "y": 0.8, "z": 0.15},
|
||||
"velocity": {"x": 0.3, "y": 0.4, "z": 0.0},
|
||||
"pattern": "circular",
|
||||
"timestamp": 1.234
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user