---
title: Drone Delivery Env β Drone Delivery OpenEnv
emoji: π
colorFrom: indigo
colorTo: purple
sdk: docker
app_port: 8000
pinned: true
license: mit
tags:
- reinforcement-learning
- drone-navigation
- openenv
- deep-q-network
- fastapi
- pytorch
- autonomous-agents
- grid-world
short_description: Autonomous drone delivery RL environment.
---
---
## π Table of Contents
- [Overview](#overview)
- [System Architecture](#system-architecture)
- [Environment Mechanics](#environment-mechanics)
- [Neural Intelligence Layer](#neural-intelligence-layer)
- [API Reference](#api-reference)
- [Quickstart](#quickstart)
- [Training](#training)
- [LLM-Powered Inference](#llm-powered-inference)
- [Docker Deployment](#docker-deployment)
- [Hugging Face Submission](#hugging-face-submission)
- [Reward Engineering](#reward-engineering)
- [Grading & Evaluation](#grading--evaluation)
- [Project Structure](#project-structure)
- [Configuration Reference](#configuration-reference)
---
## π Overview
**Drone Delivery Env** is a production-grade, OpenEnv-compatible simulation framework designed for research in deep reinforcement learning and autonomous decision-making. It provides a realistic urban delivery scenario where agents must navigate procedurally generated city grids, avoid obstacles, manage battery resources, and complete multi-waypoint delivery missions.
The framework supports three operational modes:
| Mode | Description | Entry Point |
|------|-------------|-------------|
| **Deep RL Training** | Train a `PathQNet` DQN agent from scratch | `train.py` |
| **LLM-Guided Inference** | Drive the agent via any OpenAI-compatible LLM (e.g., Qwen, GPT-4) | `inference.py` |
| **Interactive Server** | REST API + browser-based dashboard | `server/app.py` |
---
## ποΈ System Architecture
The codebase follows a clean separation-of-concerns architecture across four distinct layers:
```
drone_env/
β
βββ core/ # Physics & simulation engine
β βββ drone.py # Movement kinematics, battery drain
β βββ grid_generator.py # Procedural city map generation (PyTorch RNG)
β βββ obstacles.py # Collision detection & terrain classification
β βββ state_manager.py # Episodic state initialization (UUID-based)
β βββ graders.py # Unified scoring functions per difficulty
β βββ tasks.py # Hyper-parameter configs: easy / medium / hard
β
βββ rl/ # Neural intelligence layer
β βββ model.py # MapEncoder CNN + PathQNet DQN architecture
β βββ policy.py # Ξ΅-greedy policy with linear epsilon decay
β βββ trainer.py # Experience replay, episode analytics, inference
β
βββ server/ # REST API + frontend
β βββ app.py # FastAPI application, middleware, all endpoints
β βββ grid_world_environment.py # DroneDeliveryEnvironment (OpenEnv interface)
β βββ drone_env_environment.py # Legacy environment wrapper
β βββ map_generator.py # Map utility helpers
β βββ Dockerfile # Multi-stage production container
β βββ static/ # Browser-based interactive dashboard
β βββ index.html
β βββ script.js
β βββ style.css
β
βββ models.py # Pydantic schemas: DroneAction, DroneObservation, DroneState
βββ train.py # Standalone DQN training loop
βββ inference.py # LLM-agent inference runner (OpenAI-compatible)
βββ client.py # Python SDK client for the REST API
βββ openenv.yaml # OpenEnv Space manifest
βββ pyproject.toml # Package metadata and dependencies
βββ validate-submission.sh # Hugging Face submission validator
```
### Component Interaction Flow
```
LLM / RL Agent
β
β HTTP POST /step {direction: "UP"}
βΌ
βββββββββββββββββββββββββββββββββββ
β FastAPI Server (app.py) β
β ββββββββββββββββββββββββββββ β
β β DroneDeliveryEnvironmentβ β
β β ββββββββββ ββββββββββββ β β
β β β grid_ β β core/* β β β
β β β world β β physics β β β
β β ββββββββββ ββββββββββββ β β
β ββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββ
β
β DroneObservation (JSON)
βΌ
Agent processes state β next action
```
---
## π Environment Mechanics
### Grid World
Maps are procedurally generated using a **seeded PyTorch `Generator`** ensuring reproducibility. Each cell on the grid is one of seven types:
| Emoji | Type | Effect |
|-------|------|--------|
| π | Drone | Agent's current position |
| π£ | Road | Safe traversal (no penalty) |
| π’ | Building | Passable with penalty (`r_building`) |
| π³ | Tree | Passable with penalty (`r_tree`) |
| π§ | Obstacle | Passable with penalty (`r_obstacle`) |
| π¦ | Delivery Target | Collect for delivery reward |
| β
| Delivered | Completed delivery waypoint |
### Action Space
The agent selects one discrete action per timestep:
```
UP | DOWN | LEFT | RIGHT | WAIT
```
Out-of-bound moves (hitting grid walls) are penalized but keep the agent in place.
### Observation Space
Each `DroneObservation` returned after every step contains:
```python
class DroneObservation(BaseModel):
grid: List[str] # Rendered emoji grid rows
cell_types: List[List[str]] # Raw cell type matrix (for neural input)
grid_width: int
grid_height: int
drone_x: int # Current drone column
drone_y: int # Current drone row
battery: float # Normalized battery 0.0β1.0
battery_steps_remaining: int
deliveries_total: int
deliveries_done: int
current_target: Optional[Tuple[int, int]]
distance_to_target: Optional[float] # Manhattan distance
step_count: int
max_steps: int
reward_last: float
reward_total: float
score: float # Graded score 0β100
done: bool
message: str
legend: Dict[str, str]
```
### Difficulty Levels
| Parameter | `easy_delivery` | `medium_delivery` | `hard_delivery` |
|-----------|:--------------:|:-----------------:|:---------------:|
| Grid Size | 10 Γ 10 | 14 Γ 14 | 18 Γ 18 |
| Buildings | 4 | 8 | 12 |
| Trees | 4 | 6 | 10 |
| Obstacles | 3 | 6 | 10 |
| Deliveries | 1 | 3 | 5 |
| Max Steps | 60 | 100 | 160 |
| Battery | 60 | 100 | 160 |
| `r_delivery` | +1.0 | +0.8 | +0.6 |
| `r_battery_dead` | β0.5 | β0.5 | β1.0 |
---
## π§ Neural Intelligence Layer
### PathQNet Architecture
The neural model (`rl/model.py`) is a **dual-input Deep Q-Network** that fuses spatial map understanding with agent telemetry:
```
Input 1: cell_ids (B, HΓW) Input 2: telemetry (B, 5)
β β
βΌ β
ββββββββββββββββββββ β
β MapEncoder CNN β β
β Embedding(8) β β
β Conv2d(8β16) β β
β Conv2d(16β32) β β
β AdaptiveAvgPool β β
β Linear β 64 β β
ββββββββββββββββββββ β
β map_emb (B, 64) β
ββββββββββββββββββββββββββββββββββββββββ
β concat (B, 69)
βΌ
βββββββββββββββββ
β PathQNet MLP β
β Linear(128) β
β LayerNorm β
β ReLU β
β Linear(128) β
β Linear(64) β
β Linear(5) β β Q-values for 5 actions
βββββββββββββββββ
```
**Telemetry vector** (5 dims):
- `drone_x / grid_width` β normalized column position
- `drone_y / grid_height` β normalized row position
- `battery` β normalized battery level (0β1)
- `target_x / grid_width` β normalized target column
- `target_y / grid_height` β normalized target row
### Epsilon-Greedy Policy
Linear epsilon decay from **1.0 β 0.05** over a configurable number of steps (`rl/policy.py`):
```python
EpsilonGreedyPolicy(eps_start=1.0, eps_end=0.05, decay_steps=5000)
```
At each decision point, with probability `Ξ΅` the agent explores randomly; otherwise it selects `argmax Q(s, a)`.
---
## π API Reference
The FastAPI server exposes the full OpenEnv-compatible interface. Access interactive docs at `http://localhost:8000/docs`.
### Core Environment Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| `POST` | `/reset` | Reset episode; optionally specify `task_name` |
| `POST` | `/step` | Execute one action; returns `DroneObservation` |
| `GET` | `/state` | Retrieve current `DroneState` |
| `GET` | `/grade/{task_name}` | Get graded score (0.0β1.0) |
### Analytics & Monitoring
| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/analyse/{task_name}` | Episode statistics from `memory.json` |
| `GET` | `/path_history` | Step-by-step trajectory of current episode |
| `GET` | `/memory_logs` | Last 5 episode summaries |
| `GET` | `/logs` | Last 50 lines from `data/train.log` |
| `GET` | `/terminal_logs` | Live HTTP request log stream |
### Utility
| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/tasks` | List all task configs |
| `POST` | `/predict` | Get next action from trained model |
| `GET` | `/health` | Health check β `{"status": "ok", "version": "0.2.1"}` |
| `GET` | `/` | Browser dashboard (interactive UI) |
---
## β‘ Quickstart
### Prerequisites
- Python β₯ 3.10
- [`uv`](https://github.com/astral-sh/uv) package manager (recommended) or `pip`
- PyTorch β₯ 2.0
### Local Installation
```bash
# Clone the repository
git clone https://huggingface.co/spaces/manikandan-n-07/drone_env
# Install with uv (recommended β uses uv.lock for reproducibility)
uv sync
# Or with pip
pip install -e ".[dev]"
```
### Launch the Server
```bash
# Using uv (recommended)
uv run server --port 8000
# Or directly
python -m uvicorn server.app:app --host 0.0.0.0 --port 8000
```
Open `http://localhost:8000` to access the interactive dashboard.
### Python SDK Client
```python
from client import DroneEnvClient
with DroneEnvClient("http://localhost:8000") as client:
# Check server health
print(client.health())
# Run a random episode for smoke-testing
result = client.run_random_episode("easy_delivery", verbose=True)
print(f"Score: {result['score']:.4f}")
# Manual episode loop
obs = client.reset("hard_delivery")
while not obs["done"]:
obs = client.step("RIGHT") # or UP / DOWN / LEFT / WAIT
analytics = client.analyse("hard_delivery")
print(analytics)
```
---
## 𧬠Training
### DQN Training Loop
Train a `PathQNet` agent with experience replay:
```bash
# Easy task β good for initial validation
python train.py --task easy_delivery --episodes 500
# Medium task β balanced challenge
python train.py --task medium_delivery --episodes 1000
# Hard task β full complexity, GPU recommended
python train.py --task hard_delivery --episodes 2000 --gpu
```
**Hyperparameters (configurable in `train.py`):**
| Parameter | Value | Description |
|-----------|-------|-------------|
| `GAMMA` | 0.99 | Discount factor |
| `BATCH_SIZE` | 64 | Experience replay batch size |
| `LR` | 1e-4 | Adam optimizer learning rate |
| `REPLAY_SIZE` | 10,000 | Replay buffer capacity |
| `TARGET_UPDATE` | 10 | Episodes between target network sync |
| `EPS_START` | 1.0 | Initial exploration rate |
| `EPS_END` | 0.05 | Minimum exploration rate |
| `EPS_DECAY` | 0.995 | Multiplicative decay per episode |
### Checkpointing & Resumption
Models are saved automatically every 50 episodes to `data/{task_short}.pth`:
```
data/easy.pth β easy_delivery checkpoint
data/medium.pth β medium_delivery checkpoint
data/hard.pth β hard_delivery checkpoint
```
Training **automatically resumes** from the latest checkpoint if one exists. To force fresh training, delete the corresponding `.pth` file.
### Training Logs
Monitor training progress in real time:
```bash
# Live log stream
tail -f data/train.log
# Or via the API
curl http://localhost:8000/logs
```
---
## π€ LLM-Powered Inference
`inference.py` provides a fully OpenAI-compatible runner that drives the drone environment using any hosted LLM.
### Configuration
Set the following environment variables (or edit `.env`):
```bash
# Option A: Hugging Face Inference Router (default β free tier)
HF_TOKEN=hf_your_token_here
# Option B: OpenAI-compatible endpoint
OPENAI_API_KEY=sk-your-key
API_BASE_URL=https://api.openai.com/v1
# Model selection (default: Qwen/Qwen2.5-7B-Instruct)
MODEL_NAME=Qwen/Qwen2.5-72B-Instruct
# Task difficulty
DRONE_TASK=easy_delivery
```
### Supported Models
| Model | Provider | Tier | Notes |
|-------|----------|------|-------|
| `Qwen/Qwen2.5-7B-Instruct` | HF Router | Free | Fast, good baseline |
| `Qwen/Qwen2.5-72B-Instruct` | HF Router | Credits | High capability |
| `Qwen/QwQ-32B-Preview` | HF Router | Credits | Reasoning-optimized |
| `gpt-4o` | OpenAI | Paid | Reference performance |
### Run Inference
```bash
# Using HF token (set in .env)
python inference.py
# Override model at runtime
MODEL_NAME=Qwen/Qwen2.5-72B-Instruct python inference.py
```
### Output Format
The runner emits structured benchmark-compatible log lines:
```
[START] task=easy_delivery env=drone_env_v1 model=Qwen/Qwen2.5-7B-Instruct
[STEP] step=1 action=RIGHT reward=-0.05 done=false error=null
[STEP] step=2 action=DOWN reward=-0.05 done=false error=null
...
[END] success=true steps=23 score=0.847 rewards=-0.05,-0.05,1.00,...
```
### System Prompt
The LLM receives a minimal, action-focused system prompt:
```
You are a drone navigation AI. Your goal is to deliver all packages.
Actions: UP, DOWN, LEFT, RIGHT, WAIT.
Respond with exactly ONE action name in uppercase.
```
And a concise per-step user prompt with position, battery, target, and distance.
---
## π³ Docker Deployment
### Build & Run Locally
```bash
# Build from the server/ directory
docker build -t drone-env -f server/Dockerfile .
# Run with health check
docker run -p 8000:8000 \
-e HF_TOKEN=hf_your_token \
drone-env
```
### Multi-Stage Build Details
The `server/Dockerfile` uses a two-stage build:
1. **Builder stage** β installs all Python dependencies via `uv sync` with layer caching
2. **Runtime stage** β copies only the virtual environment and application code
```dockerfile
# Health check built in
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:8000/health || exit 1
# Entrypoint
CMD ["sh", "-c", "cd /app/env && uvicorn server.app:app --host 0.0.0.0 --port 8000"]
```
---
## π€ Hugging Face Submission
### Space Manifest (`openenv.yaml`)
```yaml
spec_version: 1
name: drone-env
type: space
runtime: fastapi
app: server.app:app
port: 8000
```
### Validate Before Submission
The included validator script checks three things end-to-end:
1. **HF Space is live** β pings your Space's `/reset` endpoint
2. **Docker build succeeds** β runs a local `docker build`
3. **OpenEnv validation passes** β runs `openenv validate`
```bash
chmod +x validate-submission.sh
# Usage
./validate-submission.sh https://your-space.hf.space [./repo-dir]
# Example
./validate-submission.sh https://manikandan-n-07-drone-env.hf.space .
```
A passing run produces:
```
========================================
All 3/3 checks passed!
Your submission is ready to submit.
========================================
```
### Push to Hugging Face Hub
```bash
# Install the HF CLI
pip install huggingface_hub
# Login
huggingface-cli login
# Create a new Space (Docker SDK)
huggingface-cli repo create drone-env --type space --space-sdk docker
# Add the HF remote and push
git remote add hf https://huggingface.co/spaces/manikandan-n-07/drone-env
git push hf main
```
---
## π Reward Engineering
The environment uses a **composite reward signal** combining sparse terminal rewards and dense shaping:
$$R_t = r_{\text{step}} + r_{\text{shaping}} + r_{\text{terminal}}$$
| Component | Formula | Purpose |
|-----------|---------|---------|
| $r_{\text{step}}$ | $-0.05$ (constant) | Temporal pressure β discourages lingering |
| $r_{\text{shaping}}$ | $\Delta d \times 0.05$ | Manhattan-distance potential β dense guidance toward target |
| $r_{\text{wall}}$ | $-0.20$ | Out-of-bounds penalty |
| $r_{\text{obstacle}}$ | $-0.10$ to $-0.20$ | Terrain avoidance signal |
| $r_{\text{delivery}}$ | $+1.0$ to $+0.6$ | Sparse reward β scales with difficulty |
| $r_{\text{battery\_dead}}$ | $-0.5$ to $-1.0$ | Terminal failure penalty |
Reward shaping uses the **potential-based function**:
$$r_{\text{shaping}} = (d_{\text{before}} - d_{\text{after}}) \times 0.05$$
---
## π Grading & Evaluation
Scores are computed by `core/graders.py` using a unified formula:
$$\text{score} = 0.8 \times \underbrace{\frac{\text{deliveries\_done}}{\text{deliveries\_total}}}_{\text{delivery ratio}} + 0.2 \times \underbrace{\left( 0.5 \cdot \text{battery} + 0.5 \cdot \left(1 - \frac{\text{steps}}{\text{max\_steps}}\right) \right)}_{\text{efficiency}}$$
---
## π Project Structure
```
drone_env/
βββ core/
β βββ drone.py # compute_next_pos(), drain_battery()
β βββ graders.py # grade_easy/medium/hard(), GRADERS dict
β βββ grid_generator.py # generate_city_map(), EMOJI, LEGEND
β βββ obstacles.py # check_move() β outcome, cell_type
β βββ state_manager.py # new_episode_state() β DroneState
β βββ tasks.py # TASK_CONFIG dict (all difficulty params)
βββ rl/
β βββ model.py # MapEncoder, PathQNet, ACTIONS, CELL2IDX
β βββ policy.py # EpsilonGreedyPolicy
β βββ trainer.py # record_episode(), PathLearner, get_action_from_policy()
βββ server/
β βββ app.py # FastAPI app, all routes, TerminalLogManager
β βββ grid_world_environment.py # DroneDeliveryEnvironment (OpenEnv base)
β βββ Dockerfile # Multi-stage production image
β βββ static/ # Browser dashboard (HTML/JS/CSS)
βββ data/
β βββ memory.json # Persisted episode history (last 100 episodes)
β βββ train.log # Training progress log
βββ tests/
β βββ test_api.py # API integration tests
β βββ test_env.py # Environment unit tests
βββ models.py # DroneAction, DroneObservation, DroneState (Pydantic)
βββ train.py # DQN training entry point
βββ inference.py # LLM inference runner
βββ client.py # Python HTTP client SDK
βββ openenv.yaml # HF Space manifest
βββ pyproject.toml # Package config & dependencies
βββ validate-submission.sh # Pre-submission validation script
```
---
## βοΈ Configuration Reference
### `pyproject.toml` Dependencies
```toml
[project]
name = "drone-env"
version = "0.2.0"
requires-python = ">=3.10"
dependencies = [
"openenv-core[core]>=0.2.1",
"torch>=2.0.0",
"openai>=1.0.0",
"python-multipart>=0.0.9",
]
```
### Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `HF_TOKEN` | β | Hugging Face API token for LLM inference |
| `OPENAI_API_KEY` | β | OpenAI API key (alternative to HF) |
| `API_BASE_URL` | HF Router URL | Override LLM endpoint |
| `MODEL_NAME` | `Qwen/Qwen2.5-7B-Instruct` | LLM model identifier |
| `DRONE_TASK` | `easy_delivery` | Default task for inference runner |
| `LOCAL_IMAGE_NAME` | `drone-inference-v1` | Local Docker image tag |
---
## π§ͺ Testing
```bash
# Run all tests
uv run pytest tests/ -v
# With coverage report
uv run pytest tests/ --cov=. --cov-report=html
# Specific test files
uv run pytest tests/test_env.py -v
uv run pytest tests/test_api.py -v
```
---
## π€ Contributing
1. Fork the repository on Hugging Face Hub
2. Create a feature branch: `git checkout -b feat/your-feature`
3. Commit your changes with descriptive messages
4. Run the test suite and validator before submitting
5. Open a Pull Request against `main`
---
## π License
This project is licensed under the **MIT License**. See `LICENSE` for details.
Build system uses [Meta's BSD-licensed](https://opensource.org/licenses/BSD-3-Clause) `setuptools` configuration template.
---
**Built with π for the OpenEnv ecosystem**
*Advancing autonomous agent research through high-fidelity simulation*