evangelosmeklis commited on
Commit
57c13e3
·
1 Parent(s): 9ce2f95

major refactor of the deepdrone repo, to be a CLI agent

Browse files
.env-example DELETED
@@ -1,8 +0,0 @@
1
- # DeepDrone Environment Variables
2
- # Make a copy of this file and name it '.env', then fill in your API tokens
3
-
4
- # Hugging Face API token (required for AI functionality)
5
- # Get your token at https://huggingface.co/settings/tokens
6
- HF_TOKEN=your_huggingface_token_here
7
-
8
- # Add any additional API keys or environment variables below
 
 
 
 
 
 
 
 
 
README.md CHANGED
@@ -1,53 +1,198 @@
1
- ---
2
- title: DeepDrone
3
- emoji: 🚁
4
- colorFrom: green
5
- colorTo: green
6
- sdk: streamlit
7
- sdk_version: 1.41.1
8
- app_file: main.py
9
- pinned: false
10
- ---
11
 
12
- # DeepDrone
13
 
14
- A drone chat agent for drone analytics and operations, built on the smolagents framework with DroneKit integration for real drone control.
15
 
16
- ![DeepDrone Interface](https://i.imgur.com/5ZfQW8i.png)
17
- ![DeepDrone Visualization](https://i.imgur.com/h3zmVIz.png)
 
 
 
 
18
 
 
 
 
 
 
 
19
 
20
- ## Features
 
 
 
 
21
 
22
- - **Drone Chat**: Interact with a drone assistant through a chat interface
23
- - **Visualizations**: Generate flight paths and sensor readings visualizations
24
- - **Maintenance Recommendations**: Get maintenance suggestions based on flight hours
25
- - **Mission Planning**: Generate mission plans for various drone operations
26
- - **Real Drone Control**: Connect to and control real drones using DroneKit
27
- - Take off and land
28
- - Navigate to GPS coordinates
29
- - Return to home
30
- - Execute waypoint missions
31
- - Monitor battery and location
32
 
33
- ## Getting Started
34
 
35
- 1. Clone this repository
36
- 2. Copy `.env-example` to `.env` and add your Hugging Face API token
37
- 3. Install dependencies: `pip install -r requirements.txt`
38
- 4. **For Python 3.10+ users**: Run the compatibility patch: `python dronekit_patch.py`
39
- 5. Run the application: `streamlit run main.py`
40
 
41
- ## Using DroneKit Integration
 
 
 
42
 
43
- The DroneKit integration allows you to control drones running ArduPilot or PX4 firmware.
 
 
 
44
 
45
- ### Python 3.10+ Compatibility
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
- If you're using Python 3.10 or newer, you need to run the patch script before using DroneKit:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
 
 
 
 
 
 
 
 
49
  ```
50
- python dronekit_patch.py
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  ```
52
 
53
  This script fixes the "AttributeError: module 'collections' has no attribute 'MutableMapping'" error by patching the DroneKit library to use collections.abc instead of collections.
 
1
+ # 🚁 DeepDrone - AI-Powered Drone Control Terminal
 
 
 
 
 
 
 
 
 
2
 
3
+ A powerful terminal-based application for controlling drones using various AI models including OpenAI, Anthropic, Hugging Face, and local Ollama models. Built with DroneKit integration for real drone control.
4
 
5
+ ## Features
6
 
7
+ ### 🤖 Multi-Model AI Support
8
+ - **OpenAI**: GPT-3.5, GPT-4, and other OpenAI models
9
+ - **Anthropic**: Claude 3 models
10
+ - **Ollama**: Local models (Llama 3.1, Codestral, etc.)
11
+ - **Hugging Face**: Any model available through their API
12
+ - **LiteLLM**: Unified interface for all providers
13
 
14
+ ### 🚁 Drone Control & Operations
15
+ - **Real Drone Control**: Connect to and control real drones using DroneKit
16
+ - **Flight Operations**: Take off, land, navigate to GPS coordinates
17
+ - **Mission Planning**: Execute complex waypoint missions
18
+ - **Safety Features**: Return to home, emergency stop
19
+ - **Telemetry**: Monitor battery, location, and flight status
20
 
21
+ ### 💻 Terminal Interface
22
+ - **Rich CLI**: Beautiful command-line interface with colors and formatting
23
+ - **Interactive Chat**: Natural language conversation with AI models
24
+ - **Model Management**: Easy switching between different AI models
25
+ - **Configuration**: Persistent settings and API key management
26
 
27
+ ## 🚀 Quick Start
 
 
 
 
 
 
 
 
 
28
 
29
+ ### Installation
30
 
31
+ 1. **Clone the repository**
32
+ ```bash
33
+ git clone <repository-url>
34
+ cd deepdrone
35
+ ```
36
 
37
+ 2. **Install dependencies**
38
+ ```bash
39
+ pip install -r requirements.txt
40
+ ```
41
 
42
+ 3. **Start the interactive session**
43
+ ```bash
44
+ python main.py
45
+ ```
46
 
47
+ ### Interactive Setup
48
+
49
+ When you run `python main.py`, DeepDrone will guide you through:
50
+
51
+ 1. **🔮 Provider Selection** - Choose from OpenAI, Anthropic, Google, Meta, Mistral, or Ollama
52
+ 2. **🤖 Model Selection** - Pick from popular models or enter your own
53
+ 3. **🔑 API Key Entry** - Securely enter your API credentials (Ollama skips this)
54
+ 4. **✅ Connection Test** - Verify everything works
55
+ 5. **🚁 Simulator Setup** - Instructions for drone connection
56
+ 6. **💬 Chat Interface** - Start controlling your drone with natural language
57
+
58
+ ### Command Line Usage (Advanced)
59
+
60
+ For advanced users who prefer command-line options:
61
+
62
+ ```bash
63
+ # List available models
64
+ python main.py models list
65
+
66
+ # Add API keys for cloud models
67
+ python main.py models set-key gpt-3.5-turbo
68
+
69
+ # Start a specific chat session
70
+ python main.py chat -m gpt-3.5-turbo
71
+
72
+ # Check Ollama models (for local AI)
73
+ python main.py ollama check
74
 
75
+ # View configuration
76
+ python main.py config
77
+ ```
78
+
79
+ ## 🛠️ Configuration
80
+
81
+ ### Setting Up AI Models
82
+
83
+ #### OpenAI Models
84
+ ```bash
85
+ # Add your OpenAI API key
86
+ python main.py models set-key gpt-3.5-turbo
87
+ # Get API key from: https://platform.openai.com/api-keys
88
+ ```
89
+
90
+ #### Anthropic Models
91
+ ```bash
92
+ # Add your Anthropic API key
93
+ python main.py models set-key claude-3-sonnet
94
+ # Get API key from: https://console.anthropic.com/
95
+ ```
96
 
97
+ #### Local Ollama Models
98
+ ```bash
99
+ # First install and run Ollama: https://ollama.ai
100
+ ollama pull llama3.1
101
+ ollama pull codestral
102
+
103
+ # Check available models
104
+ python main.py ollama check
105
  ```
106
+
107
+ ### Drone Connection
108
+
109
+ #### Using the Built-in Simulator
110
+
111
+ **🎯 Quick Start:**
112
+ 1. Open a new terminal and run:
113
+ ```bash
114
+ python simulate_drone.py
115
+ ```
116
+ 2. The simulator will display a connection string like `udp:127.0.0.1:14550`
117
+ 3. In DeepDrone chat, use that connection string to connect
118
+
119
+ #### Real Drone Connections
120
+
121
+ For real drones:
122
+ - **Serial**: `/dev/ttyACM0` (Linux) or `COM3` (Windows)
123
+ - **TCP**: `tcp:192.168.1.100:5760`
124
+ - **UDP**: `udp:127.0.0.1:14550`
125
+
126
+ #### Professional Simulation
127
+
128
+ For advanced simulation, install ArduPilot SITL:
129
+ ```bash
130
+ # Get installation help
131
+ python simulate_drone.py --install-help
132
+ ```
133
+
134
+ ## 🎯 Usage Examples
135
+
136
+ ### Basic Chat
137
+ ```bash
138
+ # Start chat with GPT-3.5
139
+ python main.py chat -m gpt-3.5-turbo
140
+
141
+ # Start chat with local Ollama model
142
+ python main.py chat -m llama3.1
143
+ ```
144
+
145
+ ### Interactive Chat Session
146
+
147
+ Once in the chat interface, you can control your drone with natural language:
148
+
149
+ ```
150
+ ╭─────────────── DeepDrone Control Center ───────────────╮
151
+ │ 🚁 DEEPDRONE CHAT INTERFACE │
152
+ │ │
153
+ │ AI Model: claude-3-5-sonnet (anthropic) │
154
+ │ Drone Connection: udp:127.0.0.1:14550 │
155
+ │ Status: Ready for commands │
156
+ ╰────────────────────────────────────────────────────────╯
157
+
158
+ 🚁 DeepDrone> Connect to the drone simulator and take off to 30 meters
159
+
160
+ 🤖 DeepDrone AI: I'll connect to the simulator and take off to 30 meters...
161
+ [Executes Python code to control drone]
162
+ ✅ Connected and airborne at 30 meters!
163
+
164
+ 🚁 DeepDrone> Fly in a square pattern with 50 meter sides
165
+
166
+ 🤖 DeepDrone AI: I'll create a square flight pattern...
167
+ [Plans and executes waypoint mission]
168
+ ✅ Square pattern completed!
169
+
170
+ 🚁 DeepDrone> Return home and land
171
+
172
+ 🤖 DeepDrone AI: Returning to launch point and landing safely...
173
+ ✅ Mission complete, drone landed safely!
174
+ ```
175
+
176
+ ### Model Management
177
+ ```bash
178
+ # Add a custom model
179
+ python main.py models add my-gpt4 openai gpt-4 --max-tokens 4096
180
+
181
+ # Remove a model
182
+ python main.py models remove my-gpt4
183
+
184
+ # View configuration
185
+ python main.py config
186
+ ```
187
+
188
+ ## 🛡️ DroneKit Integration
189
+
190
+ ### Python 3.10+ Compatibility
191
+
192
+ If you're using Python 3.10 or newer, run the patch script:
193
+
194
+ ```bash
195
+ python drone/dronekit_patch.py
196
  ```
197
 
198
  This script fixes the "AttributeError: module 'collections' has no attribute 'MutableMapping'" error by patching the DroneKit library to use collections.abc instead of collections.
drone/__init__.py CHANGED
@@ -4,9 +4,11 @@ Drone control and interface module.
4
  This package contains all the drone-related functionality including:
5
  - DroneKit integration
6
  - Drone control and mission planning
7
- - Chat interface for natural language interactions with the drone
 
8
  """
9
 
10
  # Import main components for easier access
11
  from .drone_control import DroneController, connect_drone, disconnect_drone, takeoff, land, return_home
12
- from .drone_chat import DroneAssistant, generate_mission_plan
 
 
4
  This package contains all the drone-related functionality including:
5
  - DroneKit integration
6
  - Drone control and mission planning
7
+ - Terminal interface for natural language interactions with the drone
8
+ - LiteLLM and Ollama integration for various AI models
9
  """
10
 
11
  # Import main components for easier access
12
  from .drone_control import DroneController, connect_drone, disconnect_drone, takeoff, land, return_home
13
+ from .config import config_manager
14
+ from .drone_tools import DroneToolsManager
drone/cli.py ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Command Line Interface for DeepDrone terminal application.
3
+ """
4
+
5
+ import typer
6
+ from rich.console import Console
7
+ from rich.table import Table
8
+ from rich.panel import Panel
9
+ from rich.prompt import Prompt, Confirm
10
+ from rich import print as rprint
11
+ from typing import Optional
12
+ import getpass
13
+
14
+ from .config import config_manager, ModelConfig
15
+ # Import will be done inside functions to avoid circular imports
16
+
17
+ app = typer.Typer(
18
+ name="deepdrone",
19
+ help="🚁 DeepDrone - AI-Powered Drone Control Terminal",
20
+ add_completion=False
21
+ )
22
+
23
+ console = Console()
24
+
25
+ @app.command()
26
+ def chat(
27
+ model: Optional[str] = typer.Option(None, "--model", "-m", help="Model to use for chat"),
28
+ connection: Optional[str] = typer.Option(None, "--connection", "-c", help="Drone connection string")
29
+ ):
30
+ """Start interactive chat with drone AI."""
31
+
32
+ # Show welcome banner
33
+ console.print(Panel.fit(
34
+ "[bold green]🚁 DEEPDRONE TERMINAL[/bold green]\n"
35
+ "[dim]AI-Powered Drone Control System[/dim]",
36
+ border_style="bright_green"
37
+ ))
38
+
39
+ # Select model if not provided
40
+ if not model:
41
+ model = select_model()
42
+ if not model:
43
+ return
44
+
45
+ # Validate model exists
46
+ model_config = config_manager.get_model(model)
47
+ if not model_config:
48
+ console.print(f"[red]Error: Model '{model}' not found[/red]")
49
+ console.print("Use 'deepdrone models list' to see available models")
50
+ return
51
+
52
+ # Check if model needs API key
53
+ if model_config.provider in ["openai", "anthropic", "huggingface"] and not model_config.api_key:
54
+ console.print(f"[yellow]Model '{model}' requires an API key[/yellow]")
55
+ if Confirm.ask("Would you like to set it now?"):
56
+ set_api_key_interactive(model)
57
+ # Reload model config after setting API key
58
+ model_config = config_manager.get_model(model)
59
+
60
+ # Start chat
61
+ try:
62
+ from .terminal_chat import TerminalDroneChat
63
+ chat_session = TerminalDroneChat(model_config, connection)
64
+ chat_session.start()
65
+ except KeyboardInterrupt:
66
+ console.print("\n[yellow]Chat session ended[/yellow]")
67
+ except Exception as e:
68
+ console.print(f"[red]Error starting chat: {e}[/red]")
69
+
70
+ # Create models subcommand group
71
+ models_app = typer.Typer(help="Manage AI models")
72
+ app.add_typer(models_app, name="models")
73
+
74
+ @models_app.command("list")
75
+ def list_models():
76
+ """List all available models."""
77
+ models = config_manager.list_models()
78
+
79
+ if not models:
80
+ console.print("[yellow]No models configured[/yellow]")
81
+ return
82
+
83
+ table = Table(title="Available Models")
84
+ table.add_column("Name", style="cyan", no_wrap=True)
85
+ table.add_column("Provider", style="magenta")
86
+ table.add_column("Model ID", style="blue")
87
+ table.add_column("API Key", style="green")
88
+ table.add_column("Status", style="yellow")
89
+
90
+ for name in models:
91
+ config = config_manager.get_model(name)
92
+ api_key_status = "✓" if config.api_key else "✗"
93
+
94
+ # Check status
95
+ if config.provider == "ollama":
96
+ status = "Local"
97
+ elif config.api_key:
98
+ status = "Ready"
99
+ else:
100
+ status = "Needs API Key"
101
+
102
+ table.add_row(
103
+ name,
104
+ config.provider,
105
+ config.model_id,
106
+ api_key_status,
107
+ status
108
+ )
109
+
110
+ console.print(table)
111
+
112
+ # Show usage hint
113
+ console.print("\n[dim]Use 'deepdrone chat -m <model_name>' to start chatting[/dim]")
114
+
115
+ @models_app.command("add")
116
+ def add_model(
117
+ name: str = typer.Argument(..., help="Name for the model"),
118
+ provider: str = typer.Argument(..., help="Provider (openai, anthropic, ollama, etc.)"),
119
+ model_id: str = typer.Argument(..., help="Model ID/identifier"),
120
+ base_url: Optional[str] = typer.Option(None, "--base-url", help="Base URL for API"),
121
+ max_tokens: int = typer.Option(2048, "--max-tokens", help="Maximum tokens"),
122
+ temperature: float = typer.Option(0.7, "--temperature", help="Temperature setting")
123
+ ):
124
+ """Add a new model configuration."""
125
+
126
+ model_config = ModelConfig(
127
+ name=name,
128
+ provider=provider,
129
+ model_id=model_id,
130
+ base_url=base_url,
131
+ max_tokens=max_tokens,
132
+ temperature=temperature
133
+ )
134
+
135
+ config_manager.add_model(model_config)
136
+ console.print(f"[green]Model '{name}' added successfully[/green]")
137
+
138
+ # Ask for API key if needed
139
+ if provider in ["openai", "anthropic", "huggingface"]:
140
+ if Confirm.ask(f"Would you like to set the API key for '{name}' now?"):
141
+ set_api_key_interactive(name)
142
+
143
+ @models_app.command("remove")
144
+ def remove_model(name: str = typer.Argument(..., help="Name of model to remove")):
145
+ """Remove a model configuration."""
146
+
147
+ if not config_manager.get_model(name):
148
+ console.print(f"[red]Model '{name}' not found[/red]")
149
+ return
150
+
151
+ if Confirm.ask(f"Are you sure you want to remove model '{name}'?"):
152
+ if config_manager.remove_model(name):
153
+ console.print(f"[green]Model '{name}' removed successfully[/green]")
154
+ else:
155
+ console.print(f"[red]Failed to remove model '{name}'[/red]")
156
+
157
+ @models_app.command("set-key")
158
+ def set_api_key(
159
+ model: str = typer.Argument(..., help="Model name"),
160
+ key: Optional[str] = typer.Option(None, "--key", help="API key (will prompt if not provided)")
161
+ ):
162
+ """Set API key for a model."""
163
+ set_api_key_interactive(model, key)
164
+
165
+ @app.command("config")
166
+ def show_config():
167
+ """Show current configuration."""
168
+
169
+ console.print(Panel.fit(
170
+ f"[bold]Configuration Directory:[/bold] {config_manager.settings.config_dir}\n"
171
+ f"[bold]Models File:[/bold] {config_manager.settings.models_file}\n"
172
+ f"[bold]Default Model:[/bold] {config_manager.settings.default_model}\n"
173
+ f"[bold]Default Connection:[/bold] {config_manager.settings.drone.default_connection_string}",
174
+ title="DeepDrone Configuration",
175
+ border_style="blue"
176
+ ))
177
+
178
+ # Create ollama subcommand group
179
+ ollama_app = typer.Typer(help="Ollama-specific commands")
180
+ app.add_typer(ollama_app, name="ollama")
181
+
182
+ @ollama_app.command("check")
183
+ def check_ollama():
184
+ """Check if Ollama is running and list available models."""
185
+ try:
186
+ import ollama
187
+
188
+ # Try to connect to Ollama
189
+ models = ollama.list()
190
+
191
+ if not hasattr(models, 'models') or not models.models:
192
+ console.print("[yellow]Ollama is running but no models are installed[/yellow]")
193
+ console.print("Install a model with: ollama pull llama3.1")
194
+ return
195
+
196
+ table = Table(title="Ollama Models")
197
+ table.add_column("Name", style="cyan")
198
+ table.add_column("Size", style="blue")
199
+ table.add_column("Modified", style="green")
200
+
201
+ for model in models.models:
202
+ table.add_row(
203
+ model.model,
204
+ f"{model.size / (1024**3):.1f} GB" if hasattr(model, 'size') else "Unknown",
205
+ str(model.modified_at)[:19] if hasattr(model, 'modified_at') else 'Unknown'
206
+ )
207
+
208
+ console.print(table)
209
+ console.print("\n[dim]Use 'deepdrone models add <name> ollama <model_name>' to add to DeepDrone[/dim]")
210
+
211
+ except ImportError:
212
+ console.print("[red]Ollama Python package not installed[/red]")
213
+ console.print("Install with: pip install ollama")
214
+ except Exception as e:
215
+ console.print(f"[red]Error connecting to Ollama: {e}[/red]")
216
+ console.print("Make sure Ollama is running: ollama serve")
217
+
218
+ def select_model() -> Optional[str]:
219
+ """Interactive model selection."""
220
+ models = config_manager.list_models()
221
+
222
+ if not models:
223
+ console.print("[red]No models configured[/red]")
224
+ console.print("Use 'deepdrone models add' to add a model")
225
+ return None
226
+
227
+ console.print("\n[bold]Available Models:[/bold]")
228
+ for i, model_name in enumerate(models, 1):
229
+ config = config_manager.get_model(model_name)
230
+ status = "✓" if config.api_key or config.provider == "ollama" else "⚠ (needs API key)"
231
+ console.print(f" {i}. {model_name} ({config.provider}) {status}")
232
+
233
+ while True:
234
+ try:
235
+ choice = Prompt.ask(
236
+ "\nSelect model",
237
+ choices=[str(i) for i in range(1, len(models) + 1)] + models,
238
+ default="1"
239
+ )
240
+
241
+ if choice.isdigit():
242
+ return models[int(choice) - 1]
243
+ elif choice in models:
244
+ return choice
245
+ except (ValueError, IndexError):
246
+ console.print("[red]Invalid selection[/red]")
247
+
248
+ def set_api_key_interactive(model_name: str, api_key: Optional[str] = None):
249
+ """Set API key interactively."""
250
+ model_config = config_manager.get_model(model_name)
251
+ if not model_config:
252
+ console.print(f"[red]Model '{model_name}' not found[/red]")
253
+ return
254
+
255
+ if model_config.provider == "ollama":
256
+ console.print(f"[yellow]Model '{model_name}' is an Ollama model and doesn't need an API key[/yellow]")
257
+ return
258
+
259
+ if not api_key:
260
+ console.print(f"\n[bold]Setting API key for {model_name} ({model_config.provider})[/bold]")
261
+
262
+ if model_config.provider == "openai":
263
+ console.print("Get your OpenAI API key from: https://platform.openai.com/api-keys")
264
+ elif model_config.provider == "anthropic":
265
+ console.print("Get your Anthropic API key from: https://console.anthropic.com/")
266
+ elif model_config.provider == "huggingface":
267
+ console.print("Get your Hugging Face token from: https://huggingface.co/settings/tokens")
268
+
269
+ api_key = getpass.getpass("Enter API key (hidden): ")
270
+
271
+ if api_key.strip():
272
+ if config_manager.set_api_key(model_name, api_key.strip()):
273
+ console.print(f"[green]API key set for '{model_name}'[/green]")
274
+ else:
275
+ console.print(f"[red]Failed to set API key for '{model_name}'[/red]")
276
+ else:
277
+ console.print("[yellow]No API key provided[/yellow]")
278
+
279
+ if __name__ == "__main__":
280
+ app()
drone/config.py ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Configuration management for DeepDrone terminal application.
3
+ """
4
+
5
+ import os
6
+ import json
7
+ from pathlib import Path
8
+ from typing import Dict, Optional, List
9
+ from pydantic import BaseModel, Field
10
+ from pydantic_settings import BaseSettings
11
+
12
+ class ModelConfig(BaseModel):
13
+ """Configuration for a specific model."""
14
+ name: str
15
+ provider: str # 'openai', 'anthropic', 'ollama', 'huggingface', etc.
16
+ api_key: Optional[str] = None
17
+ base_url: Optional[str] = None
18
+ model_id: str
19
+ max_tokens: int = 2048
20
+ temperature: float = 0.7
21
+
22
+ class DroneConfig(BaseModel):
23
+ """Configuration for drone connection."""
24
+ default_connection_string: str = "udp:127.0.0.1:14550"
25
+ timeout: int = 30
26
+ default_altitude: float = 30.0
27
+ max_altitude: float = 100.0
28
+
29
+ class AppSettings(BaseSettings):
30
+ """Main application settings."""
31
+
32
+ # File paths
33
+ config_dir: Path = Field(default_factory=lambda: Path.home() / ".deepdrone")
34
+ models_file: Path = Field(default_factory=lambda: Path.home() / ".deepdrone" / "models.json")
35
+
36
+ # Default model
37
+ default_model: str = "gpt-3.5-turbo"
38
+
39
+ # Drone settings
40
+ drone: DroneConfig = Field(default_factory=DroneConfig)
41
+
42
+ # Terminal settings
43
+ show_thinking: bool = True
44
+ auto_save_chat: bool = True
45
+ chat_history_limit: int = 100
46
+
47
+ class Config:
48
+ env_prefix = "DEEPDRONE_"
49
+ env_file = ".env"
50
+ extra = "ignore" # Ignore extra environment variables
51
+
52
+ class ConfigManager:
53
+ """Manages application configuration and model settings."""
54
+
55
+ def __init__(self):
56
+ self.settings = AppSettings()
57
+ self.models: Dict[str, ModelConfig] = {}
58
+ self._ensure_config_dir()
59
+ self._load_models()
60
+
61
+ def _ensure_config_dir(self):
62
+ """Ensure configuration directory exists."""
63
+ self.settings.config_dir.mkdir(exist_ok=True)
64
+
65
+ def _load_models(self):
66
+ """Load model configurations from file."""
67
+ if self.settings.models_file.exists():
68
+ try:
69
+ with open(self.settings.models_file, 'r') as f:
70
+ models_data = json.load(f)
71
+ self.models = {
72
+ name: ModelConfig(**config)
73
+ for name, config in models_data.items()
74
+ }
75
+ except Exception as e:
76
+ print(f"Error loading models config: {e}")
77
+ self.models = {}
78
+ else:
79
+ # Create default models
80
+ self._create_default_models()
81
+
82
+ def _create_default_models(self):
83
+ """Create default model configurations."""
84
+ self.models = {
85
+ "gpt-3.5-turbo": ModelConfig(
86
+ name="gpt-3.5-turbo",
87
+ provider="openai",
88
+ model_id="gpt-3.5-turbo",
89
+ max_tokens=2048,
90
+ temperature=0.7
91
+ ),
92
+ "gpt-4": ModelConfig(
93
+ name="gpt-4",
94
+ provider="openai",
95
+ model_id="gpt-4",
96
+ max_tokens=2048,
97
+ temperature=0.7
98
+ ),
99
+ "claude-3-sonnet": ModelConfig(
100
+ name="claude-3-sonnet",
101
+ provider="anthropic",
102
+ model_id="claude-3-sonnet-20240229",
103
+ max_tokens=2048,
104
+ temperature=0.7
105
+ ),
106
+ "llama3.1": ModelConfig(
107
+ name="llama3.1",
108
+ provider="ollama",
109
+ model_id="llama3.1:latest",
110
+ base_url="http://localhost:11434",
111
+ max_tokens=2048,
112
+ temperature=0.7
113
+ ),
114
+ "codestral": ModelConfig(
115
+ name="codestral",
116
+ provider="ollama",
117
+ model_id="codestral:latest",
118
+ base_url="http://localhost:11434",
119
+ max_tokens=2048,
120
+ temperature=0.7
121
+ )
122
+ }
123
+ self.save_models()
124
+
125
+ def save_models(self):
126
+ """Save model configurations to file."""
127
+ try:
128
+ models_data = {
129
+ name: config.model_dump()
130
+ for name, config in self.models.items()
131
+ }
132
+ with open(self.settings.models_file, 'w') as f:
133
+ json.dump(models_data, f, indent=2)
134
+ except Exception as e:
135
+ print(f"Error saving models config: {e}")
136
+
137
+ def add_model(self, config: ModelConfig):
138
+ """Add a new model configuration."""
139
+ self.models[config.name] = config
140
+ self.save_models()
141
+
142
+ def remove_model(self, name: str) -> bool:
143
+ """Remove a model configuration."""
144
+ if name in self.models:
145
+ del self.models[name]
146
+ self.save_models()
147
+ return True
148
+ return False
149
+
150
+ def get_model(self, name: str) -> Optional[ModelConfig]:
151
+ """Get a model configuration by name."""
152
+ return self.models.get(name)
153
+
154
+ def list_models(self) -> List[str]:
155
+ """List all available model names."""
156
+ return list(self.models.keys())
157
+
158
+ def set_api_key(self, model_name: str, api_key: str) -> bool:
159
+ """Set API key for a model."""
160
+ if model_name in self.models:
161
+ self.models[model_name].api_key = api_key
162
+ self.save_models()
163
+ return True
164
+ return False
165
+
166
+ def get_ollama_models(self) -> List[str]:
167
+ """Get list of available Ollama models."""
168
+ ollama_models = []
169
+ for name, config in self.models.items():
170
+ if config.provider == "ollama":
171
+ ollama_models.append(name)
172
+ return ollama_models
173
+
174
+ def get_api_models(self) -> List[str]:
175
+ """Get list of models that require API keys."""
176
+ api_models = []
177
+ for name, config in self.models.items():
178
+ if config.provider in ["openai", "anthropic", "huggingface"]:
179
+ api_models.append(name)
180
+ return api_models
181
+
182
+ # Global config manager instance
183
+ config_manager = ConfigManager()
drone/drone_chat_interface.py ADDED
@@ -0,0 +1,543 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Interactive drone chat interface - similar to Claude Code environment.
3
+ """
4
+
5
+ import os
6
+ import sys
7
+ import time
8
+ import threading
9
+ from typing import List, Dict, Any, Optional
10
+ from rich.console import Console
11
+ from rich.panel import Panel
12
+ from rich.text import Text
13
+ from rich.markdown import Markdown
14
+ from rich.layout import Layout
15
+ from rich.live import Live
16
+ from rich.spinner import Spinner
17
+ from rich.table import Table
18
+ from rich.align import Align
19
+ from prompt_toolkit import prompt
20
+ from prompt_toolkit.history import InMemoryHistory
21
+ from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
22
+ from prompt_toolkit.completion import WordCompleter
23
+ from prompt_toolkit.styles import Style
24
+ from prompt_toolkit.shortcuts import confirm
25
+ import re
26
+
27
+ from .config import ModelConfig
28
+ from .llm_interface import LLMInterface
29
+ from .drone_tools import DroneToolsManager
30
+
31
+ class DroneChatInterface:
32
+ """Interactive chat interface for drone control with AI."""
33
+
34
+ def __init__(self, model_config: ModelConfig, connection_string: Optional[str] = None):
35
+ self.console = Console()
36
+ self.model_config = model_config
37
+ self.connection_string = connection_string or "udp:127.0.0.1:14550"
38
+
39
+ # Initialize components
40
+ self.llm = LLMInterface(model_config)
41
+ self.drone_tools = DroneToolsManager(self.connection_string)
42
+
43
+ # Chat state
44
+ self.chat_history: List[Dict[str, str]] = []
45
+ self.session_active = True
46
+
47
+ # Setup prompt components
48
+ self.history = InMemoryHistory()
49
+ self.completer = WordCompleter([
50
+ 'connect', 'takeoff', 'land', 'fly', 'goto', 'mission', 'status',
51
+ 'battery', 'location', 'return', 'home', 'help', 'quit', 'exit',
52
+ 'emergency', 'stop', 'altitude', 'waypoint', 'navigate'
53
+ ])
54
+
55
+ self.style = Style.from_dict({
56
+ 'prompt': '#00ff00 bold',
57
+ 'input': '#ffffff',
58
+ 'completion-menu.completion': 'bg:#333333 #ffffff',
59
+ 'completion-menu.completion.current': 'bg:#00ff00 #000000 bold',
60
+ })
61
+
62
+ # Status tracking
63
+ self.last_status_update = time.time()
64
+ self.status_thread = None
65
+ self.status_running = False
66
+
67
+ def start(self):
68
+ """Start the interactive chat session."""
69
+ self._show_welcome()
70
+ self._start_status_monitor()
71
+
72
+ try:
73
+ while self.session_active:
74
+ try:
75
+ # Get user input
76
+ user_input = self._get_user_input()
77
+
78
+ if not user_input.strip():
79
+ continue
80
+
81
+ # Handle special commands
82
+ if self._handle_special_commands(user_input):
83
+ continue
84
+
85
+ # Process the message
86
+ self._process_message(user_input)
87
+
88
+ except KeyboardInterrupt:
89
+ self._handle_exit()
90
+ break
91
+ except EOFError:
92
+ self._handle_exit()
93
+ break
94
+
95
+ finally:
96
+ self._cleanup()
97
+
98
+ def _show_welcome(self):
99
+ """Show welcome message and status."""
100
+ welcome_panel = Panel(
101
+ f"""[bold green]🚁 DEEPDRONE CHAT INTERFACE[/bold green]
102
+
103
+ [bold]AI Model:[/bold] {self.model_config.name} ({self.model_config.provider})
104
+ [bold]Model ID:[/bold] {self.model_config.model_id}
105
+ [bold]Drone Connection:[/bold] {self.connection_string}
106
+ [bold]Status:[/bold] Ready for commands
107
+
108
+ [bold cyan]🎯 Available Commands:[/bold cyan]
109
+ • Natural language: "Connect to drone and take off to 30 meters"
110
+ • Status commands: "Show battery status", "What's my location?"
111
+ • Mission commands: "Fly in a square pattern", "Return home"
112
+ • Help: Type 'help' for more information
113
+ • Exit: Type 'quit' or 'exit' to end session
114
+
115
+ [dim]Type your commands below. The AI will interpret and execute drone operations.[/dim]""",
116
+ title="[bold green]DeepDrone Control Center[/bold green]",
117
+ border_style="bright_green",
118
+ padding=(1, 2)
119
+ )
120
+
121
+ self.console.print(welcome_panel)
122
+ self.console.print()
123
+
124
+ def _get_user_input(self) -> str:
125
+ """Get user input."""
126
+ try:
127
+ # Use simple input() for better compatibility
128
+ return input("🚁 DeepDrone> ")
129
+ except (KeyboardInterrupt, EOFError):
130
+ return '/quit'
131
+
132
+ def _handle_special_commands(self, command: str) -> bool:
133
+ """Handle special commands. Returns True if handled."""
134
+ cmd = command.strip().lower()
135
+
136
+ if cmd in ['/quit', '/exit', 'quit', 'exit']:
137
+ self.session_active = False
138
+ return True
139
+
140
+ elif cmd in ['/help', 'help']:
141
+ self._show_help()
142
+ return True
143
+
144
+ elif cmd in ['/status', 'status']:
145
+ self._show_detailed_status()
146
+ return True
147
+
148
+ elif cmd in ['/clear', 'clear']:
149
+ self.console.clear()
150
+ self._show_welcome()
151
+ return True
152
+
153
+ elif cmd.startswith('/connect'):
154
+ parts = cmd.split()
155
+ if len(parts) > 1:
156
+ self.connection_string = parts[1]
157
+ self._connect_drone_direct()
158
+ else:
159
+ self.console.print("[red]Usage: /connect <connection_string>[/red]")
160
+ return True
161
+
162
+ elif cmd in ['/disconnect', 'disconnect']:
163
+ self._disconnect_drone_direct()
164
+ return True
165
+
166
+ elif cmd in ['/emergency', 'emergency']:
167
+ self._emergency_stop()
168
+ return True
169
+
170
+ elif cmd in ['/ollama', 'ollama']:
171
+ self._show_ollama_status()
172
+ return True
173
+
174
+ return False
175
+
176
+ def _process_message(self, user_message: str):
177
+ """Process user message with AI and execute drone commands."""
178
+ # Add to history
179
+ self.chat_history.append({"role": "user", "content": user_message})
180
+
181
+ # Show user message
182
+ self.console.print(Panel(
183
+ user_message,
184
+ title="[bold blue]You[/bold blue]",
185
+ border_style="blue",
186
+ padding=(0, 1)
187
+ ))
188
+
189
+ # Generate AI response
190
+ with Live(
191
+ Spinner("dots", text="[green]🤖 AI is analyzing your request...[/green]"),
192
+ console=self.console,
193
+ transient=True
194
+ ) as live:
195
+
196
+ try:
197
+ # Create system prompt for drone operations
198
+ system_prompt = self._create_drone_system_prompt()
199
+
200
+ # Prepare messages for AI
201
+ messages = [{"role": "system", "content": system_prompt}]
202
+ messages.extend(self.chat_history[-10:]) # Last 10 messages for context
203
+
204
+ # Get AI response
205
+ ai_response = self.llm.chat(messages)
206
+
207
+ live.stop()
208
+
209
+ # Process the response for drone commands
210
+ self._process_ai_response(ai_response)
211
+
212
+ # Add to history
213
+ self.chat_history.append({"role": "assistant", "content": ai_response})
214
+
215
+ except Exception as e:
216
+ live.stop()
217
+ self.console.print(f"[red]❌ Error processing request: {e}[/red]")
218
+
219
+ def _create_drone_system_prompt(self) -> str:
220
+ """Create system prompt for drone operations."""
221
+ return f"""You are DeepDrone AI, an advanced drone control assistant. You can control real drones through Python code.
222
+
223
+ Current drone status:
224
+ - Connected: {'Yes' if self.drone_tools.is_connected() else 'No'}
225
+ - Connection: {self.connection_string}
226
+ - Mission active: {'Yes' if self.drone_tools.mission_in_progress else 'No'}
227
+
228
+ Available drone functions (use these in Python code blocks):
229
+ - connect_drone(connection_string): Connect to drone
230
+ - takeoff(altitude): Take off to specified altitude in meters
231
+ - land(): Land the drone
232
+ - return_home(): Return to launch point
233
+ - fly_to(lat, lon, alt): Fly to GPS coordinates
234
+ - get_location(): Get current GPS position
235
+ - get_battery(): Get battery status
236
+ - execute_mission(waypoints): Execute mission with waypoints list
237
+ - disconnect_drone(): Disconnect from drone
238
+
239
+ When user asks for drone operations:
240
+ 1. Explain what you'll do
241
+ 2. Provide Python code in ```python code blocks
242
+ 3. The code will be executed automatically
243
+ 4. Provide status updates
244
+
245
+ Example response:
246
+ "I'll connect to the drone and take off to 30 meters altitude.
247
+
248
+ ```python
249
+ # Connect to the drone
250
+ connect_drone('{self.connection_string}')
251
+
252
+ # Take off to 30 meters
253
+ takeoff(30)
254
+
255
+ # Get status
256
+ location = get_location()
257
+ battery = get_battery()
258
+ print(f"Location: {{location}}")
259
+ print(f"Battery: {{battery}}")
260
+ ```
261
+
262
+ The drone should now be airborne at 30 meters altitude."
263
+
264
+ Always prioritize safety and explain each operation clearly."""
265
+
266
+ def _process_ai_response(self, response: str):
267
+ """Process AI response and execute any drone commands."""
268
+ # Show AI response
269
+ if any(marker in response for marker in ['**', '*', '```', '#', '-', '1.']):
270
+ content = Markdown(response)
271
+ else:
272
+ content = Text(response)
273
+
274
+ self.console.print(Panel(
275
+ content,
276
+ title="[bold green]🤖 DeepDrone AI[/bold green]",
277
+ border_style="green",
278
+ padding=(0, 1)
279
+ ))
280
+
281
+ # Extract and execute Python code blocks
282
+ code_blocks = self._extract_code_blocks(response)
283
+ if code_blocks:
284
+ self.console.print(Panel(
285
+ "[yellow]🔧 Executing drone operations...[/yellow]",
286
+ border_style="yellow"
287
+ ))
288
+
289
+ for i, code in enumerate(code_blocks, 1):
290
+ self.console.print(f"[dim]Executing code block {i}...[/dim]")
291
+ try:
292
+ result = self._execute_drone_code(code)
293
+ if result:
294
+ self.console.print(Panel(
295
+ f"[green]✅ Execution Result:[/green]\n{result}",
296
+ border_style="green"
297
+ ))
298
+ except Exception as e:
299
+ self.console.print(Panel(
300
+ f"[red]❌ Execution Error:[/red]\n{str(e)}",
301
+ border_style="red"
302
+ ))
303
+
304
+ def _extract_code_blocks(self, text: str) -> List[str]:
305
+ """Extract Python code blocks from markdown text."""
306
+ pattern = r'```(?:python)?\n(.*?)\n```'
307
+ matches = re.findall(pattern, text, re.DOTALL)
308
+ return [match.strip() for match in matches if match.strip()]
309
+
310
+ def _execute_drone_code(self, code: str) -> str:
311
+ """Execute drone code safely."""
312
+ # Create safe execution environment
313
+ safe_globals = {
314
+ '__builtins__': {
315
+ 'print': print,
316
+ 'len': len,
317
+ 'str': str,
318
+ 'int': int,
319
+ 'float': float,
320
+ 'dict': dict,
321
+ 'list': list,
322
+ 'range': range,
323
+ },
324
+ 'connect_drone': self.drone_tools.connect_drone,
325
+ 'disconnect_drone': self.drone_tools.disconnect_drone,
326
+ 'takeoff': self.drone_tools.takeoff,
327
+ 'land': self.drone_tools.land,
328
+ 'return_home': self.drone_tools.return_home,
329
+ 'fly_to': self.drone_tools.fly_to,
330
+ 'get_location': self.drone_tools.get_location,
331
+ 'get_battery': self.drone_tools.get_battery,
332
+ 'execute_mission': self.drone_tools.execute_mission,
333
+ 'time': time,
334
+ }
335
+
336
+ # Capture output
337
+ output_lines = []
338
+
339
+ def capture_print(*args, **kwargs):
340
+ output_lines.append(' '.join(str(arg) for arg in args))
341
+
342
+ safe_globals['print'] = capture_print
343
+
344
+ # Execute code
345
+ exec(code, safe_globals)
346
+
347
+ return '\n'.join(output_lines) if output_lines else "Code executed successfully"
348
+
349
+ def _show_help(self):
350
+ """Show help information."""
351
+ help_text = """[bold cyan]🚁 DeepDrone Help[/bold cyan]
352
+
353
+ [bold]Natural Language Commands:[/bold]
354
+ • "Connect to the drone simulator"
355
+ • "Take off to 30 meters altitude"
356
+ • "Fly to coordinates 37.7749, -122.4194"
357
+ • "Show me the current battery status"
358
+ • "Execute a square flight pattern"
359
+ • "Return home and land safely"
360
+
361
+ [bold]Direct Commands:[/bold]
362
+ • [cyan]/status[/cyan] - Show detailed system status
363
+ • [cyan]/connect <connection>[/cyan] - Connect to specific drone
364
+ • [cyan]/disconnect[/cyan] - Disconnect from drone
365
+ • [cyan]/emergency[/cyan] - Emergency stop
366
+ • [cyan]/ollama[/cyan] - Show Ollama status and models
367
+ • [cyan]/clear[/cyan] - Clear screen
368
+ • [cyan]/help[/cyan] - Show this help
369
+ • [cyan]/quit[/cyan] - Exit DeepDrone
370
+
371
+ [bold]Example Session:[/bold]
372
+ [dim]🚁 DeepDrone> Connect to simulator and take off to 20 meters
373
+ 🤖 AI: I'll connect to the simulator and take off to 20 meters...
374
+ 🚁 DeepDrone> Fly in a circle with 50 meter radius
375
+ 🤖 AI: I'll create a circular flight pattern...[/dim]
376
+
377
+ [bold]Tips:[/bold]
378
+ • Use arrow keys to navigate command history
379
+ • Tab completion available for common commands
380
+ • AI understands natural language - be conversational!
381
+ • Always prioritize safety in flight operations"""
382
+
383
+ self.console.print(Panel(
384
+ help_text,
385
+ title="[bold]DeepDrone Help[/bold]",
386
+ border_style="cyan",
387
+ padding=(1, 2)
388
+ ))
389
+
390
+ def _show_detailed_status(self):
391
+ """Show detailed system and drone status."""
392
+ status = self.drone_tools.get_status()
393
+
394
+ # Create status table
395
+ table = Table(title="System Status", show_header=True, header_style="bold magenta")
396
+ table.add_column("Component", style="cyan", width=20)
397
+ table.add_column("Status", style="white")
398
+ table.add_column("Details", style="yellow")
399
+
400
+ # AI Model status
401
+ table.add_row("AI Model", "✅ Online", f"{self.model_config.name} ({self.model_config.provider})")
402
+
403
+ # Drone connection
404
+ conn_status = "✅ Connected" if status["connected"] else "❌ Disconnected"
405
+ table.add_row("Drone Connection", conn_status, self.connection_string)
406
+
407
+ # Mission status
408
+ mission_status = "🚁 Active" if status["mission_in_progress"] else "⏸️ Standby"
409
+ table.add_row("Mission", mission_status, status.get("phase", "N/A"))
410
+
411
+ # Current status
412
+ table.add_row("System Status", status["status"], "")
413
+
414
+ if status["connected"]:
415
+ location = status.get("location", {})
416
+ battery = status.get("battery", {})
417
+
418
+ if not location.get("error"):
419
+ lat = location.get("latitude", "N/A")
420
+ lon = location.get("longitude", "N/A")
421
+ alt = location.get("altitude", "N/A")
422
+ table.add_row("Location", "📍 GPS Lock", f"Lat: {lat}, Lon: {lon}, Alt: {alt}m")
423
+
424
+ if not battery.get("error"):
425
+ voltage = battery.get("voltage", "N/A")
426
+ level = battery.get("level", "N/A")
427
+ table.add_row("Battery", "🔋 Monitoring", f"Voltage: {voltage}V, Level: {level}%")
428
+
429
+ self.console.print(table)
430
+
431
+ # Show recent log entries
432
+ if status.get("log_entries"):
433
+ self.console.print("\n[bold]Recent Activity:[/bold]")
434
+ for entry in status["log_entries"][-5:]:
435
+ self.console.print(f"[dim]{entry}[/dim]")
436
+
437
+ def _connect_drone_direct(self):
438
+ """Connect to drone directly."""
439
+ with Live(
440
+ Spinner("dots", text=f"Connecting to {self.connection_string}..."),
441
+ console=self.console,
442
+ transient=True
443
+ ) as live:
444
+
445
+ success = self.drone_tools.connect_drone(self.connection_string)
446
+ live.stop()
447
+
448
+ if success:
449
+ self.console.print(f"[green]✅ Connected to drone at {self.connection_string}[/green]")
450
+ else:
451
+ self.console.print(f"[red]❌ Failed to connect to {self.connection_string}[/red]")
452
+
453
+ def _disconnect_drone_direct(self):
454
+ """Disconnect from drone directly."""
455
+ if self.drone_tools.is_connected():
456
+ self.drone_tools.disconnect_drone()
457
+ self.console.print("[yellow]📡 Disconnected from drone[/yellow]")
458
+ else:
459
+ self.console.print("[yellow]No active drone connection[/yellow]")
460
+
461
+ def _emergency_stop(self):
462
+ """Emergency stop operation."""
463
+ if self.drone_tools.is_connected():
464
+ self.console.print("[red]🚨 EMERGENCY STOP INITIATED[/red]")
465
+ self.drone_tools.emergency_stop()
466
+ else:
467
+ self.console.print("[yellow]No active drone connection for emergency stop[/yellow]")
468
+
469
+ def _start_status_monitor(self):
470
+ """Start background status monitoring."""
471
+ self.status_running = True
472
+ self.status_thread = threading.Thread(target=self._status_monitor_loop, daemon=True)
473
+ self.status_thread.start()
474
+
475
+ def _status_monitor_loop(self):
476
+ """Background status monitoring loop."""
477
+ while self.status_running and self.session_active:
478
+ try:
479
+ time.sleep(5) # Update every 5 seconds
480
+ # Could update status bar here if needed
481
+ except Exception:
482
+ break
483
+
484
+ def _handle_exit(self):
485
+ """Handle session exit."""
486
+ self.console.print("\n[yellow]🚁 Shutting down DeepDrone...[/yellow]")
487
+
488
+ if self.drone_tools.is_connected():
489
+ from rich.prompt import Confirm
490
+ if Confirm.ask("Disconnect from drone before exit?", default=True):
491
+ self.drone_tools.disconnect_drone()
492
+
493
+ self.session_active = False
494
+
495
+ def _show_ollama_status(self):
496
+ """Show Ollama status and available models."""
497
+ try:
498
+ import ollama
499
+
500
+ # Check connection
501
+ try:
502
+ models_response = ollama.list()
503
+ available_models = models_response.models if hasattr(models_response, 'models') else []
504
+
505
+ self.console.print("[bold green]✅ Ollama Status: Connected[/bold green]\n")
506
+
507
+ if available_models:
508
+ self.console.print(f"[bold]📚 Available Models ({len(available_models)}):[/bold]")
509
+ for model in available_models:
510
+ name = model.model
511
+ size = model.size if hasattr(model, 'size') else 0
512
+ size_gb = size / (1024**3) if size else 0
513
+ modified = str(model.modified_at)[:19] if hasattr(model, 'modified_at') else 'Unknown'
514
+
515
+ self.console.print(f" • [green]{name}[/green] ([blue]{size_gb:.1f} GB[/blue]) - {modified}")
516
+ else:
517
+ self.console.print("[yellow]📭 No models installed[/yellow]")
518
+ self.console.print("\n💡 Install a model with:")
519
+ self.console.print(" [cyan]ollama pull llama3.1[/cyan]")
520
+ self.console.print(" [cyan]ollama pull codestral[/cyan]")
521
+ self.console.print(" [cyan]ollama pull qwen2.5-coder[/cyan]")
522
+
523
+ self.console.print(f"\n[dim]Current model: {self.model_config.model_id}[/dim]")
524
+
525
+ except Exception as e:
526
+ self.console.print("[red]❌ Ollama Status: Not connected[/red]")
527
+ self.console.print(f"[red]Error: {e}[/red]\n")
528
+ self.console.print("💡 Make sure Ollama is running:")
529
+ self.console.print(" [cyan]ollama serve[/cyan]\n")
530
+ self.console.print("📥 Download Ollama from:")
531
+ self.console.print(" [cyan]https://ollama.com/download[/cyan]")
532
+
533
+ except ImportError:
534
+ self.console.print("[red]❌ Ollama package not installed[/red]")
535
+ self.console.print("Install with: [cyan]pip install ollama[/cyan]")
536
+
537
+ def _cleanup(self):
538
+ """Cleanup resources."""
539
+ self.status_running = False
540
+ if self.drone_tools.is_connected():
541
+ self.drone_tools.disconnect_drone()
542
+
543
+ self.console.print("[green]🚁 DeepDrone session ended. Fly safe![/green]")
drone/drone_tools.py ADDED
@@ -0,0 +1,342 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Drone tools manager for terminal interface.
3
+ Adapts the existing drone control functionality for the terminal application.
4
+ """
5
+
6
+ import time
7
+ import logging
8
+ from typing import Dict, List, Optional, Any
9
+ from .drone_control import DroneController
10
+
11
+ # Set up logging
12
+ logging.basicConfig(level=logging.INFO)
13
+ logger = logging.getLogger(__name__)
14
+
15
+ class DroneToolsManager:
16
+ """Manages drone operations for the terminal interface."""
17
+
18
+ def __init__(self, connection_string: Optional[str] = None):
19
+ self.controller = DroneController(connection_string)
20
+ self.connected = False
21
+ self.mission_in_progress = False
22
+
23
+ # Status tracking
24
+ self.status = "STANDBY"
25
+ self.phase = ""
26
+ self.log_entries = []
27
+
28
+ def connect_drone(self, connection_string: str, timeout: int = 30) -> bool:
29
+ """Connect to a drone."""
30
+ try:
31
+ self._update_status("CONNECTING", f"Connecting to {connection_string}")
32
+
33
+ success = self.controller.connect_to_drone(connection_string, timeout)
34
+ if success:
35
+ self.connected = True
36
+ self._update_status("CONNECTED", "Successfully connected to drone")
37
+
38
+ # Get initial status
39
+ location = self.get_location()
40
+ battery = self.get_battery()
41
+
42
+ logger.info(f"Connected to drone. Location: {location}, Battery: {battery}")
43
+ return True
44
+ else:
45
+ self._update_status("ERROR", "Failed to connect to drone")
46
+ return False
47
+
48
+ except Exception as e:
49
+ self._update_status("ERROR", f"Connection error: {str(e)}")
50
+ logger.error(f"Connection error: {e}")
51
+ return False
52
+
53
+ def disconnect_drone(self):
54
+ """Disconnect from the drone."""
55
+ try:
56
+ self._update_status("DISCONNECTING", "Disconnecting from drone")
57
+ self.controller.disconnect()
58
+ self.connected = False
59
+ self.mission_in_progress = False
60
+ self._update_status("STANDBY", "Disconnected from drone")
61
+ logger.info("Disconnected from drone")
62
+ except Exception as e:
63
+ logger.error(f"Disconnect error: {e}")
64
+
65
+ def takeoff(self, altitude: float) -> bool:
66
+ """Take off to specified altitude."""
67
+ if not self._ensure_connected():
68
+ return False
69
+
70
+ try:
71
+ self._update_status("TAKING OFF", f"Taking off to {altitude} meters")
72
+ self.mission_in_progress = True
73
+
74
+ success = self.controller.arm_and_takeoff(altitude)
75
+ if success:
76
+ self._update_status("AIRBORNE", f"Reached altitude of {altitude} meters")
77
+ return True
78
+ else:
79
+ self._update_status("ERROR", "Takeoff failed")
80
+ self.mission_in_progress = False
81
+ return False
82
+
83
+ except Exception as e:
84
+ self._update_status("ERROR", f"Takeoff error: {str(e)}")
85
+ self.mission_in_progress = False
86
+ logger.error(f"Takeoff error: {e}")
87
+ return False
88
+
89
+ def land(self) -> bool:
90
+ """Land the drone."""
91
+ if not self._ensure_connected():
92
+ return False
93
+
94
+ try:
95
+ self._update_status("LANDING", "Landing drone")
96
+
97
+ success = self.controller.land()
98
+ if success:
99
+ self._update_status("LANDED", "Drone has landed")
100
+ self.mission_in_progress = False
101
+ return True
102
+ else:
103
+ self._update_status("ERROR", "Landing failed")
104
+ return False
105
+
106
+ except Exception as e:
107
+ self._update_status("ERROR", f"Landing error: {str(e)}")
108
+ logger.error(f"Landing error: {e}")
109
+ return False
110
+
111
+ def return_home(self) -> bool:
112
+ """Return to launch/home location."""
113
+ if not self._ensure_connected():
114
+ return False
115
+
116
+ try:
117
+ self._update_status("RETURNING", "Returning to launch point")
118
+
119
+ success = self.controller.return_to_launch()
120
+ if success:
121
+ self._update_status("RETURNING", "Drone is returning to launch point")
122
+ return True
123
+ else:
124
+ self._update_status("ERROR", "Return to home failed")
125
+ return False
126
+
127
+ except Exception as e:
128
+ self._update_status("ERROR", f"Return error: {str(e)}")
129
+ logger.error(f"Return error: {e}")
130
+ return False
131
+
132
+ def fly_to(self, latitude: float, longitude: float, altitude: float) -> bool:
133
+ """Fly to specific GPS coordinates."""
134
+ if not self._ensure_connected():
135
+ return False
136
+
137
+ try:
138
+ self._update_status(
139
+ "NAVIGATING",
140
+ f"Flying to lat:{latitude:.4f}, lon:{longitude:.4f}, alt:{altitude}m"
141
+ )
142
+
143
+ success = self.controller.goto_location(latitude, longitude, altitude)
144
+ if success:
145
+ return True
146
+ else:
147
+ self._update_status("ERROR", "Navigation failed")
148
+ return False
149
+
150
+ except Exception as e:
151
+ self._update_status("ERROR", f"Navigation error: {str(e)}")
152
+ logger.error(f"Navigation error: {e}")
153
+ return False
154
+
155
+ def get_location(self) -> Dict[str, Any]:
156
+ """Get current GPS location."""
157
+ if not self._ensure_connected():
158
+ return {"error": "Not connected to drone"}
159
+
160
+ try:
161
+ return self.controller.get_current_location()
162
+ except Exception as e:
163
+ logger.error(f"Location error: {e}")
164
+ return {"error": str(e)}
165
+
166
+ def get_battery(self) -> Dict[str, Any]:
167
+ """Get battery status."""
168
+ if not self._ensure_connected():
169
+ return {"error": "Not connected to drone"}
170
+
171
+ try:
172
+ return self.controller.get_battery_status()
173
+ except Exception as e:
174
+ logger.error(f"Battery error: {e}")
175
+ return {"error": str(e)}
176
+
177
+ def execute_mission(self, waypoints: List[Dict[str, float]]) -> bool:
178
+ """Execute a mission with multiple waypoints."""
179
+ if not self._ensure_connected():
180
+ return False
181
+
182
+ if not waypoints:
183
+ logger.error("No waypoints provided")
184
+ return False
185
+
186
+ try:
187
+ self._update_status("MISSION", f"Starting mission with {len(waypoints)} waypoints")
188
+ self.mission_in_progress = True
189
+
190
+ # Upload mission
191
+ upload_success = self.controller.upload_mission(waypoints)
192
+ if not upload_success:
193
+ self._update_status("ERROR", "Failed to upload mission")
194
+ self.mission_in_progress = False
195
+ return False
196
+
197
+ # Execute mission
198
+ execute_success = self.controller.execute_mission()
199
+ if execute_success:
200
+ self._update_status("EXECUTING", "Mission execution started")
201
+
202
+ # Simulate mission progress updates
203
+ for i, wp in enumerate(waypoints, 1):
204
+ self._update_status(
205
+ "EXECUTING",
206
+ f"Waypoint {i}/{len(waypoints)}: {wp['lat']:.4f}, {wp['lon']:.4f}"
207
+ )
208
+ time.sleep(1) # Brief pause between waypoints
209
+
210
+ self._update_status("MISSION COMPLETE", "All waypoints reached")
211
+ return True
212
+ else:
213
+ self._update_status("ERROR", "Failed to start mission execution")
214
+ self.mission_in_progress = False
215
+ return False
216
+
217
+ except Exception as e:
218
+ self._update_status("ERROR", f"Mission error: {str(e)}")
219
+ self.mission_in_progress = False
220
+ logger.error(f"Mission error: {e}")
221
+ return False
222
+
223
+ def get_status(self) -> Dict[str, Any]:
224
+ """Get current drone and system status."""
225
+ status_info = {
226
+ "connected": self.connected,
227
+ "mission_in_progress": self.mission_in_progress,
228
+ "status": self.status,
229
+ "phase": self.phase,
230
+ "log_entries": self.log_entries[-5:], # Last 5 entries
231
+ }
232
+
233
+ if self.connected:
234
+ try:
235
+ status_info["location"] = self.get_location()
236
+ status_info["battery"] = self.get_battery()
237
+
238
+ if hasattr(self.controller, 'vehicle') and self.controller.vehicle:
239
+ status_info["mode"] = str(self.controller.vehicle.mode.name)
240
+ status_info["armed"] = self.controller.vehicle.armed
241
+ status_info["system_status"] = str(self.controller.vehicle.system_status.state)
242
+
243
+ except Exception as e:
244
+ status_info["telemetry_error"] = str(e)
245
+
246
+ return status_info
247
+
248
+ def is_connected(self) -> bool:
249
+ """Check if connected to drone."""
250
+ return self.connected
251
+
252
+ def emergency_stop(self):
253
+ """Emergency stop - immediately land or RTL."""
254
+ if not self.connected:
255
+ return
256
+
257
+ try:
258
+ self._update_status("EMERGENCY", "Emergency stop initiated")
259
+
260
+ # Try RTL first, then land
261
+ if not self.return_home():
262
+ self.land()
263
+
264
+ self.mission_in_progress = False
265
+
266
+ except Exception as e:
267
+ logger.error(f"Emergency stop error: {e}")
268
+
269
+ def set_airspeed(self, speed: float) -> bool:
270
+ """Set target airspeed."""
271
+ if not self._ensure_connected():
272
+ return False
273
+
274
+ try:
275
+ return self.controller.set_airspeed(speed)
276
+ except Exception as e:
277
+ logger.error(f"Airspeed error: {e}")
278
+ return False
279
+
280
+ def get_telemetry(self) -> Dict[str, Any]:
281
+ """Get comprehensive telemetry data."""
282
+ if not self._ensure_connected():
283
+ return {"error": "Not connected to drone"}
284
+
285
+ try:
286
+ telemetry = {}
287
+
288
+ # Basic info
289
+ telemetry["location"] = self.get_location()
290
+ telemetry["battery"] = self.get_battery()
291
+
292
+ # Vehicle-specific data if available
293
+ if hasattr(self.controller, 'vehicle') and self.controller.vehicle:
294
+ vehicle = self.controller.vehicle
295
+
296
+ telemetry.update({
297
+ "mode": str(vehicle.mode.name),
298
+ "armed": vehicle.armed,
299
+ "system_status": str(vehicle.system_status.state),
300
+ "airspeed": vehicle.airspeed,
301
+ "groundspeed": vehicle.groundspeed,
302
+ "heading": vehicle.heading,
303
+ })
304
+
305
+ # GPS info
306
+ if vehicle.gps_0:
307
+ telemetry["gps"] = {
308
+ "fix_type": vehicle.gps_0.fix_type,
309
+ "satellites_visible": vehicle.gps_0.satellites_visible,
310
+ "eph": vehicle.gps_0.eph,
311
+ "epv": vehicle.gps_0.epv,
312
+ }
313
+
314
+ return telemetry
315
+
316
+ except Exception as e:
317
+ logger.error(f"Telemetry error: {e}")
318
+ return {"error": str(e)}
319
+
320
+ def _ensure_connected(self) -> bool:
321
+ """Ensure drone is connected."""
322
+ if not self.connected:
323
+ logger.error("Not connected to drone")
324
+ return False
325
+ return True
326
+
327
+ def _update_status(self, status: str, phase: str = ""):
328
+ """Update system status and log entry."""
329
+ self.status = status
330
+ self.phase = phase
331
+
332
+ # Create log entry
333
+ timestamp = time.strftime("%H:%M:%S")
334
+ log_entry = f"[{timestamp}] {status}: {phase}" if phase else f"[{timestamp}] {status}"
335
+
336
+ self.log_entries.append(log_entry)
337
+
338
+ # Keep only last 50 entries
339
+ if len(self.log_entries) > 50:
340
+ self.log_entries = self.log_entries[-50:]
341
+
342
+ logger.info(log_entry)
drone/interactive_setup.py ADDED
@@ -0,0 +1,414 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Interactive setup and chat interface for DeepDrone.
3
+ """
4
+
5
+ import os
6
+ import sys
7
+ import asyncio
8
+ from typing import Dict, Optional, Tuple, List
9
+ from rich.console import Console
10
+ from rich.panel import Panel
11
+ from rich.text import Text
12
+ from rich.align import Align
13
+ from rich.prompt import Prompt, Confirm
14
+ from rich.table import Table
15
+ from rich.live import Live
16
+ from rich.layout import Layout
17
+ from rich.spinner import Spinner
18
+ from prompt_toolkit import prompt
19
+ from prompt_toolkit.shortcuts import radiolist_dialog, input_dialog, message_dialog
20
+ from prompt_toolkit.styles import Style
21
+ import getpass
22
+
23
+ from .config import ModelConfig
24
+ from .drone_chat_interface import DroneChatInterface
25
+
26
+ console = Console()
27
+
28
+ # Provider configurations
29
+ PROVIDERS = {
30
+ "OpenAI": {
31
+ "name": "openai",
32
+ "models": ["gpt-4o", "gpt-4o-mini", "gpt-4-turbo", "gpt-3.5-turbo"],
33
+ "api_key_url": "https://platform.openai.com/api-keys",
34
+ "description": "GPT models from OpenAI"
35
+ },
36
+ "Anthropic": {
37
+ "name": "anthropic",
38
+ "models": ["claude-3-5-sonnet-20241022", "claude-3-sonnet-20240229", "claude-3-haiku-20240307"],
39
+ "api_key_url": "https://console.anthropic.com/",
40
+ "description": "Claude models from Anthropic"
41
+ },
42
+ "Google": {
43
+ "name": "vertex_ai",
44
+ "models": ["gemini-1.5-pro", "gemini-1.5-flash", "gemini-pro"],
45
+ "api_key_url": "https://console.cloud.google.com/",
46
+ "description": "Gemini models from Google"
47
+ },
48
+ "Meta": {
49
+ "name": "openai", # Using OpenAI format for Llama models via providers
50
+ "models": ["meta-llama/Meta-Llama-3.1-70B-Instruct", "meta-llama/Meta-Llama-3.1-8B-Instruct"],
51
+ "api_key_url": "https://together.ai/ or https://replicate.com/",
52
+ "description": "Llama models from Meta (via Together.ai/Replicate)"
53
+ },
54
+ "Mistral": {
55
+ "name": "mistral",
56
+ "models": ["mistral-large-latest", "mistral-medium-latest", "mistral-small-latest"],
57
+ "api_key_url": "https://console.mistral.ai/",
58
+ "description": "Mistral AI models"
59
+ },
60
+ "Ollama": {
61
+ "name": "ollama",
62
+ "models": ["llama3.1:latest", "codestral:latest", "qwen2.5-coder:latest", "phi3:latest"],
63
+ "api_key_url": "https://ollama.ai/ (No API key needed - runs locally)",
64
+ "description": "Local models via Ollama (no API key required)"
65
+ }
66
+ }
67
+
68
+ def show_welcome_banner():
69
+ """Display the welcome banner."""
70
+ banner = """
71
+ ╔══════════════════════════════════════════════════════════╗
72
+ ║ ║
73
+ ║ 🚁 DEEPDRONE AI CONTROL SYSTEM 🚁 ║
74
+ ║ ║
75
+ ║ Advanced Drone Control with AI Integration ║
76
+ ║ ║
77
+ ╚══════════════════════════════════════════════════════════╝
78
+ """
79
+
80
+ console.print(Panel(
81
+ Align.center(Text(banner.strip(), style="bold green")),
82
+ border_style="bright_green",
83
+ padding=(1, 2)
84
+ ))
85
+
86
+ def select_provider() -> Optional[Tuple[str, Dict]]:
87
+ """Interactive provider selection."""
88
+ console.print("\n[bold cyan]📡 Select AI Provider[/bold cyan]\n")
89
+
90
+ # Create provider table for display
91
+ table = Table(show_header=True, header_style="bold magenta")
92
+ table.add_column("№", style="bright_green", width=3)
93
+ table.add_column("Provider", style="cyan", width=12)
94
+ table.add_column("Description", style="white")
95
+ table.add_column("Example Models", style="yellow")
96
+
97
+ provider_list = list(PROVIDERS.items())
98
+
99
+ for i, (name, config) in enumerate(provider_list, 1):
100
+ example_models = ", ".join(config["models"][:2])
101
+ if len(config["models"]) > 2:
102
+ example_models += "..."
103
+ table.add_row(str(i), name, config["description"], example_models)
104
+
105
+ console.print(table)
106
+ console.print()
107
+
108
+ try:
109
+ from rich.prompt import IntPrompt
110
+
111
+ choice = IntPrompt.ask(
112
+ "Select provider by number",
113
+ choices=[str(i) for i in range(1, len(provider_list) + 1)],
114
+ default=1
115
+ )
116
+
117
+ provider_name, provider_config = provider_list[choice - 1]
118
+ return provider_name, provider_config
119
+
120
+ except KeyboardInterrupt:
121
+ console.print("\n[yellow]Selection cancelled[/yellow]")
122
+ return None
123
+
124
+ def get_available_ollama_models() -> List[str]:
125
+ """Get list of locally available Ollama models."""
126
+ try:
127
+ import ollama
128
+ models = ollama.list()
129
+ # The models are returned as Model objects with a 'model' attribute
130
+ return [model.model for model in models.models] if hasattr(models, 'models') else []
131
+ except ImportError:
132
+ return []
133
+ except Exception as e:
134
+ # For debugging, you can uncomment the next line
135
+ # print(f"Error getting Ollama models: {e}")
136
+ return []
137
+
138
+ def install_ollama_model(model_name: str) -> bool:
139
+ """Install an Ollama model."""
140
+ try:
141
+ import ollama
142
+ console.print(f"[yellow]📥 Installing {model_name}... This may take a few minutes.[/yellow]")
143
+
144
+ with Live(
145
+ Spinner("dots", text=f"Installing {model_name}..."),
146
+ console=console,
147
+ transient=True
148
+ ) as live:
149
+ ollama.pull(model_name)
150
+ live.stop()
151
+
152
+ console.print(f"[green]✅ Successfully installed {model_name}[/green]")
153
+ return True
154
+ except ImportError:
155
+ console.print("[red]❌ Ollama package not installed[/red]")
156
+ return False
157
+ except Exception as e:
158
+ console.print(f"[red]❌ Failed to install {model_name}: {e}[/red]")
159
+ return False
160
+
161
+ def get_model_name(provider_name: str, provider_config: Dict) -> Optional[str]:
162
+ """Get model name from user."""
163
+ console.print(f"\n[bold cyan]🤖 Select Model for {provider_name}[/bold cyan]\n")
164
+
165
+ # Special handling for Ollama
166
+ if provider_name.lower() == "ollama":
167
+ # Check if Ollama is running and get local models
168
+ local_models = get_available_ollama_models()
169
+
170
+ if local_models:
171
+ console.print("[bold green]✅ Local Ollama models found:[/bold green]")
172
+ for i, model in enumerate(local_models, 1):
173
+ console.print(f" {i}. [green]{model}[/green]")
174
+
175
+ console.print("\n[bold]Popular models (if not installed locally):[/bold]")
176
+ start_idx = len(local_models) + 1
177
+ for i, model in enumerate(provider_config["models"], start_idx):
178
+ console.print(f" {i}. [blue]{model}[/blue] [dim](will be downloaded)[/dim]")
179
+
180
+ all_options = local_models + provider_config["models"]
181
+
182
+ else:
183
+ console.print("[yellow]⚠️ No local Ollama models found or Ollama not running[/yellow]")
184
+ console.print("Make sure Ollama is running: [cyan]ollama serve[/cyan]\n")
185
+ console.print("[bold]Popular models (will be downloaded):[/bold]")
186
+ all_options = provider_config["models"]
187
+ for i, model in enumerate(all_options, 1):
188
+ console.print(f" {i}. [blue]{model}[/blue] [dim](will be downloaded)[/dim]")
189
+
190
+ console.print(f"\n[dim]Download from: {provider_config['api_key_url']}[/dim]\n")
191
+
192
+ try:
193
+ from rich.prompt import Prompt
194
+
195
+ result = Prompt.ask(
196
+ "Enter model name or number from list above",
197
+ default="1"
198
+ )
199
+
200
+ if result:
201
+ # Check if user entered a number (selecting from list)
202
+ try:
203
+ choice_num = int(result.strip())
204
+ if 1 <= choice_num <= len(all_options):
205
+ selected_model = all_options[choice_num - 1]
206
+
207
+ # Check if model needs to be installed
208
+ if selected_model not in local_models:
209
+ console.print(f"[yellow]Model '{selected_model}' not found locally.[/yellow]")
210
+ from rich.prompt import Confirm
211
+ if Confirm.ask(f"Would you like to install {selected_model}?", default=True):
212
+ if install_ollama_model(selected_model):
213
+ return selected_model
214
+ else:
215
+ return None
216
+ else:
217
+ console.print("[yellow]Model installation cancelled[/yellow]")
218
+ return None
219
+
220
+ return selected_model
221
+ except ValueError:
222
+ pass
223
+
224
+ # User entered a custom model name
225
+ model_name = result.strip()
226
+ if model_name not in local_models:
227
+ console.print(f"[yellow]Model '{model_name}' not found locally.[/yellow]")
228
+ from rich.prompt import Confirm
229
+ if Confirm.ask(f"Would you like to install {model_name}?", default=True):
230
+ if install_ollama_model(model_name):
231
+ return model_name
232
+ else:
233
+ return None
234
+ else:
235
+ console.print("[yellow]Model installation cancelled[/yellow]")
236
+ return None
237
+
238
+ return model_name
239
+
240
+ return None
241
+
242
+ except KeyboardInterrupt:
243
+ console.print("\n[yellow]Input cancelled[/yellow]")
244
+ return None
245
+
246
+ else:
247
+ # Standard handling for other providers
248
+ console.print("[bold]Popular models for this provider:[/bold]")
249
+ for i, model in enumerate(provider_config["models"], 1):
250
+ console.print(f" {i}. [green]{model}[/green]")
251
+
252
+ console.print(f"\n[dim]Get API key from: {provider_config['api_key_url']}[/dim]\n")
253
+
254
+ try:
255
+ from rich.prompt import Prompt
256
+
257
+ result = Prompt.ask(
258
+ "Enter model name or number from list above",
259
+ default="1"
260
+ )
261
+
262
+ if result:
263
+ # Check if user entered a number (selecting from list)
264
+ try:
265
+ choice_num = int(result.strip())
266
+ if 1 <= choice_num <= len(provider_config["models"]):
267
+ return provider_config["models"][choice_num - 1]
268
+ except ValueError:
269
+ pass
270
+
271
+ # Return the entered model name
272
+ return result.strip()
273
+
274
+ return None
275
+
276
+ except KeyboardInterrupt:
277
+ console.print("\n[yellow]Input cancelled[/yellow]")
278
+ return None
279
+
280
+ def get_api_key(provider_name: str, model_name: str) -> Optional[str]:
281
+ """Get API key from user."""
282
+ console.print(f"\n[bold cyan]🔑 API Key for {provider_name}[/bold cyan]\n")
283
+ console.print(f"Model: [green]{model_name}[/green]")
284
+ console.print(f"Provider: [blue]{provider_name}[/blue]\n")
285
+
286
+ # Ollama doesn't need an API key
287
+ if provider_name.lower() == "ollama":
288
+ console.print("[green]✅ Ollama runs locally - no API key required![/green]")
289
+ console.print("[dim]Make sure Ollama is running: ollama serve[/dim]\n")
290
+ return "local" # Return a placeholder value
291
+
292
+ try:
293
+ # Use getpass for secure password input (works in all environments)
294
+ api_key = getpass.getpass("Enter your API key (hidden): ")
295
+
296
+ if api_key and api_key.strip():
297
+ return api_key.strip()
298
+
299
+ console.print("[yellow]No API key provided[/yellow]")
300
+ return None
301
+
302
+ except KeyboardInterrupt:
303
+ console.print("\n[yellow]Input cancelled[/yellow]")
304
+ return None
305
+
306
+ def test_model_connection(model_config: ModelConfig) -> bool:
307
+ """Test if the model configuration works."""
308
+ console.print(f"\n[yellow]🔍 Testing connection to {model_config.name}...[/yellow]")
309
+
310
+ try:
311
+ from .llm_interface import LLMInterface
312
+
313
+ with Live(
314
+ Spinner("dots", text="Testing API connection..."),
315
+ console=console,
316
+ transient=True
317
+ ) as live:
318
+ llm = LLMInterface(model_config)
319
+ result = llm.test_connection()
320
+
321
+ live.stop()
322
+
323
+ if result["success"]:
324
+ console.print("[green]✅ Connection successful![/green]")
325
+ console.print(f"[dim]Response: {result['response'][:100]}...[/dim]\n")
326
+ return True
327
+ else:
328
+ console.print(f"[red]❌ Connection failed: {result['error']}[/red]\n")
329
+ return False
330
+
331
+ except Exception as e:
332
+ console.print(f"[red]❌ Error testing connection: {e}[/red]\n")
333
+ return False
334
+
335
+ def start_interactive_session():
336
+ """Start the interactive setup and chat session."""
337
+ try:
338
+ # Show welcome banner
339
+ show_welcome_banner()
340
+
341
+ # Step 1: Select provider
342
+ console.print("[bold]Step 1: Choose your AI provider[/bold]\n")
343
+ provider_result = select_provider()
344
+ if not provider_result:
345
+ console.print("[yellow]Setup cancelled. Goodbye![/yellow]")
346
+ return
347
+
348
+ provider_name, provider_config = provider_result
349
+
350
+ # Step 2: Get model name
351
+ console.print(f"[bold]Step 2: Select model for {provider_name}[/bold]")
352
+ model_name = get_model_name(provider_name, provider_config)
353
+ if not model_name:
354
+ console.print("[yellow]Setup cancelled. Goodbye![/yellow]")
355
+ return
356
+
357
+ # Step 3: Get API key
358
+ console.print("[bold]Step 3: Enter API key[/bold]")
359
+ api_key = get_api_key(provider_name, model_name)
360
+ if not api_key:
361
+ console.print("[yellow]Setup cancelled. Goodbye![/yellow]")
362
+ return
363
+
364
+ # Create model configuration
365
+ base_url = None
366
+ if provider_name.lower() == "ollama":
367
+ base_url = "http://localhost:11434"
368
+
369
+ model_config = ModelConfig(
370
+ name=f"{provider_name.lower()}-session",
371
+ provider=provider_config["name"],
372
+ model_id=model_name,
373
+ api_key=api_key,
374
+ base_url=base_url,
375
+ max_tokens=2048,
376
+ temperature=0.7
377
+ )
378
+
379
+ # Step 4: Test connection
380
+ console.print("[bold]Step 4: Testing connection[/bold]")
381
+ if not test_model_connection(model_config):
382
+ if not Confirm.ask("Connection test failed. Continue anyway?"):
383
+ console.print("[yellow]Setup cancelled. Goodbye![/yellow]")
384
+ return
385
+
386
+ # Step 5: Show simulator information
387
+ console.print("[bold yellow]🚁 Drone Connection Setup[/bold yellow]\n")
388
+ console.print("To control a drone, you'll need a connection. You can:")
389
+ console.print(" 1. [green]Use Simulator[/green]: Run [cyan]python simulate_drone.py[/cyan] in another terminal")
390
+ console.print(" 2. [blue]Real Drone[/blue]: Connect via USB, TCP, or UDP")
391
+ console.print(" 3. [dim]SITL[/dim]: Use ArduPilot Software-in-the-Loop\n")
392
+
393
+ console.print("💡 [bold]Quick Start with Simulator:[/bold]")
394
+ console.print(" • Open a new terminal and run: [cyan]python simulate_drone.py[/cyan]")
395
+ console.print(" • It will show you the connection string (e.g., udp:127.0.0.1:14550)")
396
+ console.print(" • Use that connection string in the chat interface\n")
397
+
398
+ # Step 6: Start chat
399
+ console.print("[bold green]🚀 Starting DeepDrone chat session...[/bold green]\n")
400
+
401
+ # Small delay
402
+ import time
403
+ time.sleep(1)
404
+
405
+ # Start the chat interface
406
+ chat_interface = DroneChatInterface(model_config)
407
+ chat_interface.start()
408
+
409
+ except KeyboardInterrupt:
410
+ console.print("\n[yellow]🚁 DeepDrone session interrupted. Goodbye![/yellow]")
411
+ sys.exit(0)
412
+ except Exception as e:
413
+ console.print(f"[red]❌ Error in interactive session: {e}[/red]")
414
+ sys.exit(1)
drone/llm_interface.py ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ LLM Interface for DeepDrone supporting LiteLLM and Ollama.
3
+ """
4
+
5
+ import os
6
+ from typing import List, Dict, Any, Optional
7
+ import json
8
+ import logging
9
+
10
+ from .config import ModelConfig
11
+
12
+ # Set up logging
13
+ logging.basicConfig(level=logging.INFO)
14
+ logger = logging.getLogger(__name__)
15
+
16
+ class LLMInterface:
17
+ """Interface for interacting with various LLM providers."""
18
+
19
+ def __init__(self, model_config: ModelConfig):
20
+ self.model_config = model_config
21
+ self._setup_client()
22
+
23
+ def _setup_client(self):
24
+ """Set up the appropriate client based on model provider."""
25
+ if self.model_config.provider == "ollama":
26
+ self._setup_ollama()
27
+ else:
28
+ self._setup_litellm()
29
+
30
+ def _setup_ollama(self):
31
+ """Set up Ollama client."""
32
+ try:
33
+ import ollama
34
+ self.client = ollama
35
+ self.client_type = "ollama"
36
+
37
+ # Test connection
38
+ try:
39
+ models = self.client.list()
40
+ available_models = models.models if hasattr(models, 'models') else []
41
+ logger.info(f"Connected to Ollama. Available models: {len(available_models)}")
42
+
43
+ # Check if the requested model is available
44
+ model_names = [model.model for model in available_models]
45
+ if self.model_config.model_id not in model_names:
46
+ logger.warning(f"Model '{self.model_config.model_id}' not found locally. Available models: {model_names}")
47
+
48
+ except Exception as e:
49
+ logger.warning(f"Could not connect to Ollama: {e}")
50
+ logger.info("Make sure Ollama is running: ollama serve")
51
+
52
+ except ImportError:
53
+ raise ImportError("Ollama package not installed. Install with: pip install ollama")
54
+
55
+ def _setup_litellm(self):
56
+ """Set up LiteLLM client."""
57
+ try:
58
+ import litellm
59
+
60
+ # Set API key in environment if provided (skip for local/placeholder keys)
61
+ if self.model_config.api_key and self.model_config.api_key != "local":
62
+ if self.model_config.provider == "openai":
63
+ os.environ["OPENAI_API_KEY"] = self.model_config.api_key
64
+ elif self.model_config.provider == "anthropic":
65
+ os.environ["ANTHROPIC_API_KEY"] = self.model_config.api_key
66
+ elif self.model_config.provider == "huggingface":
67
+ os.environ["HUGGINGFACE_API_KEY"] = self.model_config.api_key
68
+ elif self.model_config.provider == "mistral":
69
+ os.environ["MISTRAL_API_KEY"] = self.model_config.api_key
70
+ elif self.model_config.provider == "vertex_ai":
71
+ os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = self.model_config.api_key
72
+
73
+ # Set base URL if provided
74
+ if self.model_config.base_url:
75
+ litellm.api_base = self.model_config.base_url
76
+
77
+ self.client = litellm
78
+ self.client_type = "litellm"
79
+
80
+ logger.info(f"Set up LiteLLM for {self.model_config.provider}")
81
+
82
+ except ImportError:
83
+ raise ImportError("LiteLLM package not installed. Install with: pip install litellm")
84
+
85
+ def chat(self, messages: List[Dict[str, str]]) -> str:
86
+ """Send chat messages and get response."""
87
+ try:
88
+ if self.client_type == "ollama":
89
+ return self._chat_ollama(messages)
90
+ else:
91
+ return self._chat_litellm(messages)
92
+ except Exception as e:
93
+ logger.error(f"Chat error: {e}")
94
+ return f"Error communicating with {self.model_config.provider}: {str(e)}"
95
+
96
+ def _chat_ollama(self, messages: List[Dict[str, str]]) -> str:
97
+ """Chat using Ollama."""
98
+ try:
99
+ # Convert messages to Ollama format
100
+ prompt = self._messages_to_prompt(messages)
101
+
102
+ response = self.client.generate(
103
+ model=self.model_config.model_id,
104
+ prompt=prompt,
105
+ options={
106
+ 'temperature': self.model_config.temperature,
107
+ 'num_predict': self.model_config.max_tokens,
108
+ }
109
+ )
110
+
111
+ return response['response']
112
+
113
+ except Exception as e:
114
+ error_str = str(e).lower()
115
+
116
+ if "model not found" in error_str or "model does not exist" in error_str:
117
+ available_models = []
118
+ try:
119
+ models = self.client.list()
120
+ available_models = [m.model for m in models.models] if hasattr(models, 'models') else []
121
+ except:
122
+ pass
123
+
124
+ error_msg = f"❌ Model '{self.model_config.model_id}' not found in Ollama.\n\n"
125
+
126
+ if available_models:
127
+ error_msg += f"📋 Available local models:\n"
128
+ for model in available_models:
129
+ error_msg += f" • {model}\n"
130
+ error_msg += f"\n💡 To install {self.model_config.model_id}, run:\n"
131
+ error_msg += f" ollama pull {self.model_config.model_id}\n"
132
+ else:
133
+ error_msg += "📭 No models found locally.\n\n"
134
+ error_msg += f"💡 To install {self.model_config.model_id}, run:\n"
135
+ error_msg += f" ollama pull {self.model_config.model_id}\n\n"
136
+ error_msg += "🎯 Popular models to try:\n"
137
+ error_msg += " • ollama pull llama3.1\n"
138
+ error_msg += " • ollama pull codestral\n"
139
+ error_msg += " • ollama pull qwen2.5-coder\n"
140
+
141
+ return error_msg
142
+
143
+ elif "connection" in error_str or "refused" in error_str:
144
+ return "❌ Cannot connect to Ollama.\n\n💡 Make sure Ollama is running:\n ollama serve\n\n📥 Download Ollama from: https://ollama.com/download"
145
+
146
+ return f"❌ Ollama error: {str(e)}"
147
+
148
+ def _chat_litellm(self, messages: List[Dict[str, str]]) -> str:
149
+ """Chat using LiteLLM."""
150
+ try:
151
+ response = self.client.completion(
152
+ model=self.model_config.model_id,
153
+ messages=messages,
154
+ max_tokens=self.model_config.max_tokens,
155
+ temperature=self.model_config.temperature,
156
+ )
157
+
158
+ return response.choices[0].message.content
159
+
160
+ except Exception as e:
161
+ if "api key" in str(e).lower():
162
+ return f"API key error for {self.model_config.provider}. Please set your API key with: deepdrone models set-key {self.model_config.name}"
163
+ elif "quota" in str(e).lower() or "billing" in str(e).lower():
164
+ return f"Billing/quota error for {self.model_config.provider}. Please check your account."
165
+ elif "model" in str(e).lower() and "not found" in str(e).lower():
166
+ return f"Model '{self.model_config.model_id}' not found for {self.model_config.provider}."
167
+
168
+ raise e
169
+
170
+ def _messages_to_prompt(self, messages: List[Dict[str, str]]) -> str:
171
+ """Convert messages to a single prompt for models that don't support chat format."""
172
+ prompt_parts = []
173
+
174
+ for message in messages:
175
+ role = message["role"]
176
+ content = message["content"]
177
+
178
+ if role == "system":
179
+ prompt_parts.append(f"System: {content}")
180
+ elif role == "user":
181
+ prompt_parts.append(f"Human: {content}")
182
+ elif role == "assistant":
183
+ prompt_parts.append(f"Assistant: {content}")
184
+
185
+ prompt_parts.append("Assistant: ")
186
+
187
+ return "\n\n".join(prompt_parts)
188
+
189
+ def test_connection(self) -> Dict[str, Any]:
190
+ """Test connection to the LLM service."""
191
+ try:
192
+ test_messages = [
193
+ {"role": "user", "content": "Hello, please respond with 'Connection test successful'"}
194
+ ]
195
+
196
+ response = self.chat(test_messages)
197
+
198
+ return {
199
+ "success": True,
200
+ "response": response,
201
+ "provider": self.model_config.provider,
202
+ "model": self.model_config.model_id
203
+ }
204
+
205
+ except Exception as e:
206
+ return {
207
+ "success": False,
208
+ "error": str(e),
209
+ "provider": self.model_config.provider,
210
+ "model": self.model_config.model_id
211
+ }
212
+
213
+ def get_model_info(self) -> Dict[str, Any]:
214
+ """Get information about the current model."""
215
+ info = {
216
+ "name": self.model_config.name,
217
+ "provider": self.model_config.provider,
218
+ "model_id": self.model_config.model_id,
219
+ "max_tokens": self.model_config.max_tokens,
220
+ "temperature": self.model_config.temperature,
221
+ "client_type": self.client_type,
222
+ }
223
+
224
+ if self.model_config.base_url:
225
+ info["base_url"] = self.model_config.base_url
226
+
227
+ return info
drone/terminal_chat.py ADDED
@@ -0,0 +1,496 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Terminal-based chat interface for DeepDrone with LiteLLM and Ollama support.
3
+ """
4
+
5
+ import asyncio
6
+ from typing import List, Dict, Any, Optional
7
+ from rich.console import Console
8
+ from rich.panel import Panel
9
+ from rich.text import Text
10
+ from rich.markdown import Markdown
11
+ from rich.live import Live
12
+ from rich.spinner import Spinner
13
+ from prompt_toolkit import prompt
14
+ from prompt_toolkit.shortcuts import message_dialog
15
+ from prompt_toolkit.styles import Style
16
+ import json
17
+ import time
18
+
19
+ from .config import ModelConfig
20
+ from .llm_interface import LLMInterface
21
+ from .drone_tools import DroneToolsManager
22
+
23
+ class TerminalDroneChat:
24
+ """Terminal-based chat interface for drone control."""
25
+
26
+ def __init__(self, model_config: ModelConfig, connection_string: Optional[str] = None):
27
+ self.console = Console()
28
+ self.model_config = model_config
29
+ self.connection_string = connection_string
30
+ self.chat_history: List[Dict[str, str]] = []
31
+
32
+ # Initialize LLM interface
33
+ self.llm = LLMInterface(model_config)
34
+
35
+ # Initialize drone tools
36
+ self.drone_tools = DroneToolsManager(connection_string)
37
+
38
+ # Chat settings
39
+ self.show_thinking = True
40
+ self.max_history = 50
41
+
42
+ # Style for prompt
43
+ self.prompt_style = Style.from_dict({
44
+ 'prompt': '#00ff00 bold',
45
+ 'input': '#ffffff',
46
+ })
47
+
48
+ def start(self):
49
+ """Start the interactive chat session."""
50
+ self._show_welcome()
51
+
52
+ try:
53
+ while True:
54
+ user_input = self._get_user_input()
55
+
56
+ if not user_input.strip():
57
+ continue
58
+
59
+ # Handle special commands
60
+ if user_input.startswith('/'):
61
+ if self._handle_command(user_input):
62
+ continue
63
+ else:
64
+ break
65
+
66
+ # Process user message
67
+ self._process_message(user_input)
68
+
69
+ except KeyboardInterrupt:
70
+ self._show_goodbye()
71
+ except EOFError:
72
+ self._show_goodbye()
73
+
74
+ def _show_welcome(self):
75
+ """Show welcome message and model info."""
76
+ welcome_text = f"""
77
+ [bold green]🚁 DEEPDRONE TERMINAL ACTIVE[/bold green]
78
+
79
+ [bold]Model:[/bold] {self.model_config.name} ({self.model_config.provider})
80
+ [bold]Connection:[/bold] {self.connection_string or 'Not connected'}
81
+ [bold]Status:[/bold] Ready for commands
82
+
83
+ [dim]Type your commands or questions. Use /help for available commands.[/dim]
84
+ [dim]Type /quit to exit.[/dim]
85
+ """
86
+
87
+ self.console.print(Panel(
88
+ welcome_text.strip(),
89
+ border_style="bright_green",
90
+ padding=(1, 2)
91
+ ))
92
+
93
+ def _show_goodbye(self):
94
+ """Show goodbye message."""
95
+ self.console.print("\n[yellow]🚁 DeepDrone session ended. Fly safe![/yellow]")
96
+
97
+ # Disconnect from drone if connected
98
+ if self.drone_tools.is_connected():
99
+ self.console.print("[dim]Disconnecting from drone...[/dim]")
100
+ self.drone_tools.disconnect()
101
+
102
+ def _get_user_input(self) -> str:
103
+ """Get user input with custom prompt."""
104
+ try:
105
+ return prompt(
106
+ [('class:prompt', '🚁 DeepDrone> ')],
107
+ style=self.prompt_style
108
+ )
109
+ except (KeyboardInterrupt, EOFError):
110
+ return '/quit'
111
+
112
+ def _handle_command(self, command: str) -> bool:
113
+ """Handle special commands. Returns True to continue, False to quit."""
114
+ cmd_parts = command[1:].split()
115
+ if not cmd_parts:
116
+ return True
117
+
118
+ cmd = cmd_parts[0].lower()
119
+
120
+ if cmd in ['quit', 'exit', 'q']:
121
+ return False
122
+
123
+ elif cmd == 'help':
124
+ self._show_help()
125
+
126
+ elif cmd == 'clear':
127
+ self.console.clear()
128
+ self._show_welcome()
129
+
130
+ elif cmd == 'history':
131
+ self._show_history()
132
+
133
+ elif cmd == 'status':
134
+ self._show_status()
135
+
136
+ elif cmd == 'connect':
137
+ if len(cmd_parts) > 1:
138
+ self._connect_drone(cmd_parts[1])
139
+ else:
140
+ self.console.print("[red]Usage: /connect <connection_string>[/red]")
141
+
142
+ elif cmd == 'disconnect':
143
+ self._disconnect_drone()
144
+
145
+ elif cmd == 'models':
146
+ self._show_model_info()
147
+
148
+ else:
149
+ self.console.print(f"[red]Unknown command: {command}[/red]")
150
+ self.console.print("Type /help for available commands")
151
+
152
+ return True
153
+
154
+ def _process_message(self, user_message: str):
155
+ """Process user message and generate response."""
156
+ # Add user message to history
157
+ self.chat_history.append({"role": "user", "content": user_message})
158
+
159
+ # Show user message
160
+ self.console.print(Panel(
161
+ user_message,
162
+ title="[bold blue]You[/bold blue]",
163
+ border_style="blue",
164
+ padding=(0, 1)
165
+ ))
166
+
167
+ # Check if this requires drone tools
168
+ requires_tools = self._message_requires_tools(user_message)
169
+
170
+ # Generate response
171
+ with Live(
172
+ Spinner("dots", text="[green]DeepDrone is thinking...[/green]"),
173
+ console=self.console,
174
+ transient=True
175
+ ) as live:
176
+
177
+ try:
178
+ if requires_tools:
179
+ response = self._process_with_tools(user_message, live)
180
+ else:
181
+ response = self._process_simple_chat(user_message)
182
+
183
+ live.stop()
184
+
185
+ # Show response
186
+ self._show_response(response)
187
+
188
+ # Add to history
189
+ self.chat_history.append({"role": "assistant", "content": response})
190
+
191
+ # Trim history if too long
192
+ if len(self.chat_history) > self.max_history:
193
+ self.chat_history = self.chat_history[-self.max_history:]
194
+
195
+ except Exception as e:
196
+ live.stop()
197
+ self.console.print(f"[red]Error: {e}[/red]")
198
+
199
+ def _message_requires_tools(self, message: str) -> bool:
200
+ """Check if message requires drone tools."""
201
+ tool_keywords = [
202
+ 'connect', 'takeoff', 'land', 'fly', 'goto', 'mission',
203
+ 'battery', 'location', 'status', 'arm', 'disarm', 'rtl',
204
+ 'return', 'home', 'altitude', 'waypoint', 'navigate'
205
+ ]
206
+
207
+ message_lower = message.lower()
208
+ return any(keyword in message_lower for keyword in tool_keywords)
209
+
210
+ def _process_with_tools(self, message: str, live: Live) -> str:
211
+ """Process message that may require drone tools."""
212
+ # Update status
213
+ live.update(Spinner("dots", text="[green]Analyzing command and planning actions...[/green]"))
214
+
215
+ # Create system prompt with tool information
216
+ system_prompt = self._create_system_prompt_with_tools()
217
+
218
+ # Prepare messages
219
+ messages = [{"role": "system", "content": system_prompt}]
220
+ messages.extend(self.chat_history[-10:]) # Last 10 messages for context
221
+ messages.append({"role": "user", "content": message})
222
+
223
+ # Get LLM response
224
+ response = self.llm.chat(messages)
225
+
226
+ # Check if response contains tool calls
227
+ if self._response_has_tool_calls(response):
228
+ live.update(Spinner("dots", text="[yellow]Executing drone operations...[/yellow]"))
229
+ response = self._execute_tool_calls(response)
230
+
231
+ return response
232
+
233
+ def _process_simple_chat(self, message: str) -> str:
234
+ """Process simple chat message without tools."""
235
+ system_prompt = """You are DeepDrone, an AI assistant specialized in drone operations and flight control.
236
+
237
+ You help users with:
238
+ - Drone flight planning and mission design
239
+ - Understanding drone systems and components
240
+ - Troubleshooting flight issues
241
+ - Safety protocols and regulations
242
+ - Data analysis from drone flights
243
+
244
+ Be concise, helpful, and focus on drone-related topics. If asked about your identity,
245
+ clearly state that you are DeepDrone, a specialized drone AI assistant."""
246
+
247
+ messages = [{"role": "system", "content": system_prompt}]
248
+ messages.extend(self.chat_history[-10:])
249
+ messages.append({"role": "user", "content": message})
250
+
251
+ return self.llm.chat(messages)
252
+
253
+ def _create_system_prompt_with_tools(self) -> str:
254
+ """Create system prompt with tool information."""
255
+ return """You are DeepDrone, an AI assistant that can control real drones through Python code.
256
+
257
+ Available drone control functions:
258
+ - connect_drone(connection_string): Connect to drone
259
+ - disconnect_drone(): Disconnect from drone
260
+ - takeoff(altitude): Take off to specified altitude in meters
261
+ - land(): Land the drone
262
+ - return_home(): Return to launch point
263
+ - fly_to(lat, lon, alt): Fly to GPS coordinates
264
+ - get_location(): Get current GPS position
265
+ - get_battery(): Get battery status
266
+ - execute_mission(waypoints): Execute mission with list of waypoints
267
+
268
+ When user requests drone operations, write Python code using these functions.
269
+ Always explain what you're doing and provide status updates.
270
+
271
+ Example:
272
+ ```python
273
+ # Connect to drone simulator
274
+ connect_drone('udp:127.0.0.1:14550')
275
+
276
+ # Take off to 30 meters
277
+ takeoff(30)
278
+
279
+ # Fly to a specific location
280
+ fly_to(37.7749, -122.4194, 30)
281
+
282
+ # Return home
283
+ return_home()
284
+
285
+ # Disconnect
286
+ disconnect_drone()
287
+ ```
288
+
289
+ Be safety-conscious and explain each operation."""
290
+
291
+ def _response_has_tool_calls(self, response: str) -> bool:
292
+ """Check if response contains Python code blocks."""
293
+ return "```python" in response or "```" in response
294
+
295
+ def _execute_tool_calls(self, response: str) -> str:
296
+ """Execute tool calls found in response."""
297
+ # Extract Python code blocks
298
+ code_blocks = self._extract_code_blocks(response)
299
+
300
+ results = []
301
+ for code in code_blocks:
302
+ try:
303
+ result = self._execute_code_block(code)
304
+ results.append(f"✅ Executed: {result}")
305
+ except Exception as e:
306
+ results.append(f"❌ Error: {e}")
307
+
308
+ # Append execution results to response
309
+ if results:
310
+ response += "\n\n**Execution Results:**\n" + "\n".join(results)
311
+
312
+ return response
313
+
314
+ def _extract_code_blocks(self, text: str) -> List[str]:
315
+ """Extract Python code blocks from markdown text."""
316
+ code_blocks = []
317
+ lines = text.split('\n')
318
+ in_code_block = False
319
+ current_block = []
320
+
321
+ for line in lines:
322
+ if line.strip().startswith('```python') or line.strip().startswith('```'):
323
+ if in_code_block:
324
+ # End of code block
325
+ if current_block:
326
+ code_blocks.append('\n'.join(current_block))
327
+ current_block = []
328
+ in_code_block = False
329
+ else:
330
+ # Start of code block
331
+ in_code_block = True
332
+ elif in_code_block:
333
+ current_block.append(line)
334
+
335
+ return code_blocks
336
+
337
+ def _execute_code_block(self, code: str) -> str:
338
+ """Execute a code block using drone tools."""
339
+ # Create a safe execution environment
340
+ safe_globals = {
341
+ 'connect_drone': self.drone_tools.connect_drone,
342
+ 'disconnect_drone': self.drone_tools.disconnect_drone,
343
+ 'takeoff': self.drone_tools.takeoff,
344
+ 'land': self.drone_tools.land,
345
+ 'return_home': self.drone_tools.return_home,
346
+ 'fly_to': self.drone_tools.fly_to,
347
+ 'get_location': self.drone_tools.get_location,
348
+ 'get_battery': self.drone_tools.get_battery,
349
+ 'execute_mission': self.drone_tools.execute_mission,
350
+ }
351
+
352
+ # Capture output
353
+ output = []
354
+
355
+ def capture_print(*args, **kwargs):
356
+ output.append(' '.join(str(arg) for arg in args))
357
+
358
+ safe_globals['print'] = capture_print
359
+
360
+ # Execute code
361
+ exec(code, safe_globals)
362
+
363
+ return '\n'.join(output) if output else "Command executed successfully"
364
+
365
+ def _show_response(self, response: str):
366
+ """Show AI response with formatting."""
367
+ # Parse as markdown if it contains markdown elements
368
+ if any(marker in response for marker in ['**', '*', '```', '#', '-', '1.']):
369
+ content = Markdown(response)
370
+ else:
371
+ content = Text(response)
372
+
373
+ self.console.print(Panel(
374
+ content,
375
+ title="[bold green]🚁 DeepDrone[/bold green]",
376
+ border_style="green",
377
+ padding=(0, 1)
378
+ ))
379
+
380
+ def _show_help(self):
381
+ """Show help message."""
382
+ help_text = """
383
+ [bold]Available Commands:[/bold]
384
+
385
+ [bold cyan]/help[/bold cyan] - Show this help message
386
+ [bold cyan]/quit[/bold cyan] - Exit the application
387
+ [bold cyan]/clear[/bold cyan] - Clear the screen
388
+ [bold cyan]/history[/bold cyan] - Show chat history
389
+ [bold cyan]/status[/bold cyan] - Show system status
390
+ [bold cyan]/connect <connection>[/bold cyan] - Connect to drone
391
+ [bold cyan]/disconnect[/bold cyan] - Disconnect from drone
392
+ [bold cyan]/models[/bold cyan] - Show current model info
393
+
394
+ [bold]Drone Commands (natural language):[/bold]
395
+ - "Connect to simulator at udp:127.0.0.1:14550"
396
+ - "Take off to 30 meters"
397
+ - "Fly to coordinates 37.7749, -122.4194 at 50 meters"
398
+ - "Show current location and battery status"
399
+ - "Execute a square flight pattern"
400
+ - "Return home and land"
401
+
402
+ [bold]Example Conversation:[/bold]
403
+ [dim]You: Connect to the drone simulator
404
+ DeepDrone: I'll connect to the simulator for you...
405
+ You: Take off to 20 meters and fly in a circle
406
+ DeepDrone: Taking off to 20 meters and executing circular pattern...[/dim]
407
+ """
408
+
409
+ self.console.print(Panel(
410
+ help_text.strip(),
411
+ title="[bold]DeepDrone Help[/bold]",
412
+ border_style="cyan"
413
+ ))
414
+
415
+ def _show_history(self):
416
+ """Show chat history."""
417
+ if not self.chat_history:
418
+ self.console.print("[yellow]No chat history available[/yellow]")
419
+ return
420
+
421
+ self.console.print("[bold]Chat History:[/bold]\n")
422
+
423
+ for i, msg in enumerate(self.chat_history[-10:], 1): # Last 10 messages
424
+ role_color = "blue" if msg["role"] == "user" else "green"
425
+ role_name = "You" if msg["role"] == "user" else "DeepDrone"
426
+
427
+ self.console.print(f"[{role_color}]{i}. {role_name}:[/{role_color}] {msg['content'][:100]}...")
428
+
429
+ def _show_status(self):
430
+ """Show system status."""
431
+ drone_status = "Connected" if self.drone_tools.is_connected() else "Disconnected"
432
+ drone_color = "green" if self.drone_tools.is_connected() else "red"
433
+
434
+ status_text = f"""
435
+ [bold]Model:[/bold] {self.model_config.name} ({self.model_config.provider})
436
+ [bold]Drone Status:[/bold] [{drone_color}]{drone_status}[/{drone_color}]
437
+ [bold]Connection:[/bold] {self.connection_string or 'None'}
438
+ [bold]Chat History:[/bold] {len(self.chat_history)} messages
439
+ """
440
+
441
+ if self.drone_tools.is_connected():
442
+ try:
443
+ location = self.drone_tools.get_location()
444
+ battery = self.drone_tools.get_battery()
445
+ status_text += f"""
446
+ [bold]Location:[/bold] {location}
447
+ [bold]Battery:[/bold] {battery}
448
+ """
449
+ except Exception as e:
450
+ status_text += f"\n[yellow]Could not get drone telemetry: {e}[/yellow]"
451
+
452
+ self.console.print(Panel(
453
+ status_text.strip(),
454
+ title="[bold]System Status[/bold]",
455
+ border_style="yellow"
456
+ ))
457
+
458
+ def _connect_drone(self, connection_string: str):
459
+ """Connect to drone."""
460
+ self.console.print(f"[yellow]Connecting to drone at {connection_string}...[/yellow]")
461
+
462
+ try:
463
+ if self.drone_tools.connect_drone(connection_string):
464
+ self.connection_string = connection_string
465
+ self.console.print("[green]✅ Connected to drone successfully[/green]")
466
+ else:
467
+ self.console.print("[red]❌ Failed to connect to drone[/red]")
468
+ except Exception as e:
469
+ self.console.print(f"[red]❌ Connection error: {e}[/red]")
470
+
471
+ def _disconnect_drone(self):
472
+ """Disconnect from drone."""
473
+ if self.drone_tools.is_connected():
474
+ self.drone_tools.disconnect_drone()
475
+ self.console.print("[yellow]Disconnected from drone[/yellow]")
476
+ else:
477
+ self.console.print("[yellow]No drone connection to disconnect[/yellow]")
478
+
479
+ def _show_model_info(self):
480
+ """Show current model information."""
481
+ info_text = f"""
482
+ [bold]Name:[/bold] {self.model_config.name}
483
+ [bold]Provider:[/bold] {self.model_config.provider}
484
+ [bold]Model ID:[/bold] {self.model_config.model_id}
485
+ [bold]Max Tokens:[/bold] {self.model_config.max_tokens}
486
+ [bold]Temperature:[/bold] {self.model_config.temperature}
487
+ """
488
+
489
+ if self.model_config.base_url:
490
+ info_text += f"\n[bold]Base URL:[/bold] {self.model_config.base_url}"
491
+
492
+ self.console.print(Panel(
493
+ info_text.strip(),
494
+ title="[bold]Current Model[/bold]",
495
+ border_style="magenta"
496
+ ))
eeprom.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fdba0627b42b0ddda657d4b38e46469a0b19a87dae8daa00c2da6f5f2db26bd3
3
+ size 16384
main.py CHANGED
@@ -1,218 +1,43 @@
1
- import streamlit as st
2
- import os
3
- from dotenv import load_dotenv
4
- from drone import drone_chat
5
-
6
- # Load environment variables from .env file
7
- load_dotenv()
8
-
9
- # Add dark theme CSS right at the beginning
10
- st.markdown(
11
- """
12
- <style>
13
- /* Dark theme for the entire app, applied immediately */
14
- .stApp, body, [data-testid="stAppViewContainer"], .main, .block-container, [data-testid="stHeader"] {
15
- background-color: #000000 !important;
16
- color: #00ff00 !important;
17
- }
18
-
19
- /* Dark styling for all inputs */
20
- [data-testid="stTextInput"] > div, .stTextInput > div {
21
- background-color: #1E1E1E !important;
22
- color: #00ff00 !important;
23
- border: 1px solid #00ff00 !important;
24
- }
25
-
26
- [data-testid="stTextInput"] input, .stTextInput input {
27
- color: #00ff00 !important;
28
- background-color: #1E1E1E !important;
29
- }
30
- </style>
31
- """,
32
- unsafe_allow_html=True
33
- )
34
 
35
- # Page config is set in drone_chat.py at module level
 
 
36
 
37
- # Remove duplicate page config since it's now in drone_chat.py at module level
38
- # We'll just import the module and call its main function
39
-
40
- def show_auth_screen():
41
- """Display the authentication screen with DeepDrone information"""
42
-
43
- # Military-style header
44
- st.markdown("<h1 class='glow-text' style='text-align: center; color: #00ff00; font-family: \"Courier New\", monospace; margin-top: 0; margin-bottom: 10px;'>DEEPDRONE COMMAND CENTER</h1>", unsafe_allow_html=True)
45
- st.markdown("<p class='subheader glow-text' style='text-align: center; margin-bottom: 5px;'>SECURE TACTICAL OPERATIONS INTERFACE</p>", unsafe_allow_html=True)
46
 
47
- # Create a centered container for the auth form
48
- st.markdown("<div class='auth-container'>", unsafe_allow_html=True)
49
-
50
- st.markdown("<div style='text-align: center'>", unsafe_allow_html=True)
51
- st.markdown("<h2 style='color: #00ff00; font-family: \"Courier New\", monospace; text-shadow: 0 0 5px #00ff00;'>SYSTEM AUTHENTICATION REQUIRED</h2>", unsafe_allow_html=True)
52
-
53
- # System status information in a more compact layout
54
- cols = st.columns(2)
55
- with cols[0]:
56
- st.markdown("""
57
- <div style='font-family: "Courier New", monospace; color: #00dd00;'>
58
- <b>SYSTEM STATUS:</b> STANDBY<br>
59
- <b>DATABASE:</b> CONNECTED<br>
60
- <b>SECURITY:</b> ENABLED
61
- </div>
62
- """, unsafe_allow_html=True)
63
-
64
- with cols[1]:
65
- st.markdown("""
66
- <div style='font-family: "Courier New", monospace; color: #00dd00;'>
67
- <b>PROTOCOL:</b> HF-AUTH-1<br>
68
- <b>ENCRYPTION:</b> AES-256<br>
69
- <b>AI MODULE:</b> OFFLINE
70
- </div>
71
- """, unsafe_allow_html=True)
72
-
73
- # Compact information about DeepDrone
74
- st.markdown("""
75
- <div style='font-family: "Courier New", monospace; color: #00ff00; text-align: left; margin: 15px 0;'>
76
- <p><b>DEEPDRONE</b> is an advanced command and control system for drone operations:</p>
77
-
78
- <ul style='color: #00ff00; margin: 8px 0; padding-left: 20px;'>
79
- <li>Real-time <b>flight data analysis</b> and visualization</li>
80
- <li>Comprehensive <b>sensor monitoring</b> with anomaly detection</li>
81
- <li>AI-powered <b>mission planning</b> and execution</li>
82
- <li>Predictive <b>maintenance scheduling</b> and diagnostics</li>
83
- </ul>
84
- </div>
85
- """, unsafe_allow_html=True)
86
-
87
- st.markdown("<hr style='border: 1px solid #00ff00; margin: 10px 0;'>", unsafe_allow_html=True)
88
-
89
- # Token input with custom styling
90
- st.markdown("<h3 style='color: #00ff00; font-family: \"Courier New\", monospace; text-shadow: 0 0 5px #00ff00;'>ENTER HUGGING FACE AUTHENTICATION TOKEN FOR THE LLM TO RUN:</h3>", unsafe_allow_html=True)
91
-
92
- # Create a container with dark background for the input
93
- st.markdown("<div style='background-color: #0A0A0A; padding: 10px; border-radius: 5px;'>", unsafe_allow_html=True)
94
- api_key = st.text_input("HF Token", type="password", placeholder="Enter Hugging Face API token...", label_visibility="collapsed")
95
- st.markdown("</div>", unsafe_allow_html=True)
96
-
97
- # Submit button with custom styling
98
- if st.button("AUTHORIZE ACCESS"):
99
- if api_key:
100
- os.environ["HF_TOKEN"] = api_key
101
- st.markdown("<div style='color: #00ff00; background-color: rgba(0, 128, 0, 0.2); padding: 10px; border: 1px solid #00ff00; border-radius: 5px;'>AUTHENTICATION SUCCESSFUL - INITIALIZING SYSTEM</div>", unsafe_allow_html=True)
102
- st.session_state['authenticated'] = True
103
- st.rerun()
104
-
105
- st.markdown("</div>", unsafe_allow_html=True) # Close text-align center div
106
- st.markdown("</div>", unsafe_allow_html=True) # Close auth-container div
107
 
108
  def main():
109
- # Add CSS styles
110
- st.markdown(
111
- """
112
- <style>
113
- /* Dark theme for the entire app */
114
- .stApp, body, [data-testid="stAppViewContainer"] {
115
- background-color: #000000 !important;
116
- color: #00ff00 !important;
117
- }
118
-
119
- /* Make sure all containers are dark */
120
- [data-testid="stVerticalBlock"], [data-testid="stHorizontalBlock"],
121
- [data-testid="stForm"], [data-testid="column"], .stBlock,
122
- [data-testid="stMarkdownContainer"] {
123
- background-color: #000000 !important;
124
- }
125
-
126
- /* Dark inputs */
127
- [data-testid="stTextInput"] > div {
128
- background-color: #1E1E1E !important;
129
- color: #00ff00 !important;
130
- border: 1px solid #00ff00 !important;
131
- }
132
-
133
- [data-testid="stTextInput"] input {
134
- color: #00ff00 !important;
135
- background-color: #1E1E1E !important;
136
- }
137
-
138
- /* Dark buttons */
139
- .stButton > button {
140
- background-color: #0A0A0A !important;
141
- color: #00ff00 !important;
142
- border: 1px solid #00ff00 !important;
143
- border-radius: 2px !important;
144
- font-family: "Courier New", monospace !important;
145
- }
146
-
147
- .stButton > button:hover {
148
- background-color: #00ff00 !important;
149
- color: #000000 !important;
150
- }
151
-
152
- /* Success message styling */
153
- .element-container [data-testid="stAlert"] {
154
- background-color: rgba(0, 128, 0, 0.2) !important;
155
- color: #00ff00 !important;
156
- border: 1px solid #00ff00 !important;
157
- }
158
-
159
- /* Header styling */
160
- h1, h2, h3, h4, h5, h6, p, span, div, label {
161
- color: #00ff00 !important;
162
- }
163
-
164
- /* Centered container for HF token */
165
- .auth-container {
166
- display: flex;
167
- flex-direction: column;
168
- align-items: center;
169
- justify-content: center;
170
- height: auto;
171
- min-height: 400px;
172
- max-width: 90vh;
173
- width: 70%;
174
- margin: 20px auto;
175
- padding: 30px;
176
- border: 1px solid #00ff00;
177
- border-radius: 10px;
178
- background-color: #0A0A0A !important;
179
- overflow-y: auto;
180
- }
181
-
182
- /* Hide Streamlit's default footer */
183
- footer, header {
184
- visibility: hidden !important;
185
- display: none !important;
186
- }
187
-
188
- /* Remove white background from all components */
189
- .block-container, .main {
190
- background-color: #000000 !important;
191
- }
192
-
193
- /* Add a slight glow effect to green text */
194
- .glow-text {
195
- text-shadow: 0 0 5px #00ff00 !important;
196
- }
197
-
198
- /* Custom select styling */
199
- [data-testid="stSelectbox"] {
200
- background-color: #1E1E1E !important;
201
- color: #00ff00 !important;
202
- border: 1px solid #00ff00 !important;
203
- }
204
- </style>
205
- """,
206
- unsafe_allow_html=True
207
- )
208
-
209
- # Check if user is authenticated
210
- if not os.environ.get("HF_TOKEN") and not st.session_state.get('authenticated', False):
211
- show_auth_screen()
212
- return
213
-
214
- # Run the drone chat application
215
- drone_chat.main()
216
 
217
  if __name__ == "__main__":
218
  main()
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ DeepDrone Terminal Application - AI-Powered Drone Control System
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
+ A terminal-based application for controlling drones using various AI models
6
+ including OpenAI, Anthropic, Hugging Face, and local Ollama models.
7
+ """
8
 
9
+ import sys
10
+ import os
11
+ from pathlib import Path
 
 
 
 
 
 
12
 
13
+ # Add the current directory to Python path for imports
14
+ current_dir = Path(__file__).parent
15
+ sys.path.insert(0, str(current_dir))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
  def main():
18
+ """Main entry point for the DeepDrone terminal application."""
19
+ try:
20
+ # Load environment variables if .env file exists
21
+ env_file = current_dir / ".env"
22
+ if env_file.exists():
23
+ from dotenv import load_dotenv
24
+ load_dotenv(env_file)
25
+
26
+ # If no arguments provided, start interactive mode
27
+ if len(sys.argv) == 1:
28
+ from drone.interactive_setup import start_interactive_session
29
+ start_interactive_session()
30
+ else:
31
+ # Run the Typer CLI application for other commands
32
+ from drone.cli import app
33
+ app()
34
+
35
+ except KeyboardInterrupt:
36
+ print("\n🚁 DeepDrone session interrupted. Goodbye!")
37
+ sys.exit(0)
38
+ except Exception as e:
39
+ print(f"❌ Error starting DeepDrone: {e}")
40
+ sys.exit(1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
  if __name__ == "__main__":
43
  main()
mav.parm ADDED
@@ -0,0 +1,1349 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ACRO_BAL_PITCH 1.000000
2
+ ACRO_BAL_ROLL 1.000000
3
+ ACRO_OPTIONS 0
4
+ ACRO_RP_EXPO 0.300000
5
+ ACRO_RP_RATE 360.000000
6
+ ACRO_RP_RATE_TC 0.000000
7
+ ACRO_THR_MID 0.000000
8
+ ACRO_TRAINER 2
9
+ ACRO_Y_EXPO 0.000000
10
+ ACRO_Y_RATE 202.500000
11
+ ACRO_Y_RATE_TC 0.000000
12
+ ADSB_TYPE 0
13
+ AHRS_COMP_BETA 0.100000
14
+ AHRS_EKF_TYPE 3
15
+ AHRS_GPS_GAIN 1.000000
16
+ AHRS_GPS_MINSATS 6
17
+ AHRS_GPS_USE 1
18
+ AHRS_OPTIONS 0
19
+ AHRS_ORIENTATION 0
20
+ AHRS_RP_P 0.200000
21
+ AHRS_TRIM_X 0.000000
22
+ AHRS_TRIM_Y 0.000000
23
+ AHRS_TRIM_Z 0.000000
24
+ AHRS_WIND_MAX 0
25
+ AHRS_YAW_P 0.200000
26
+ ANGLE_MAX 3000
27
+ ARMING_ACCTHRESH 0.750000
28
+ ARMING_CHECK 1
29
+ ARMING_MAGTHRESH 100
30
+ ARMING_MIS_ITEMS 0
31
+ ARMING_NEED_LOC 0
32
+ ARMING_OPTIONS 0
33
+ ARMING_RUDDER 2
34
+ ARSPD_ENABLE 0
35
+ ATC_ACCEL_P_MAX 110000.000000
36
+ ATC_ACCEL_R_MAX 110000.000000
37
+ ATC_ACCEL_Y_MAX 27000.000000
38
+ ATC_ANGLE_BOOST 1
39
+ ATC_ANG_LIM_TC 1.000000
40
+ ATC_ANG_PIT_P 4.500000
41
+ ATC_ANG_RLL_P 4.500000
42
+ ATC_ANG_YAW_P 4.500000
43
+ ATC_INPUT_TC 0.150000
44
+ ATC_LAND_P_MULT 1.000000
45
+ ATC_LAND_R_MULT 1.000000
46
+ ATC_LAND_Y_MULT 1.000000
47
+ ATC_RATE_FF_ENAB 1
48
+ ATC_RATE_P_MAX 0.000000
49
+ ATC_RATE_R_MAX 0.000000
50
+ ATC_RATE_Y_MAX 0.000000
51
+ ATC_RAT_PIT_D 0.003600
52
+ ATC_RAT_PIT_D_FF 0.000000
53
+ ATC_RAT_PIT_FF 0.000000
54
+ ATC_RAT_PIT_FLTD 20.000000
55
+ ATC_RAT_PIT_FLTE 0.000000
56
+ ATC_RAT_PIT_FLTT 20.000000
57
+ ATC_RAT_PIT_I 0.135000
58
+ ATC_RAT_PIT_IMAX 0.500000
59
+ ATC_RAT_PIT_NEF 0
60
+ ATC_RAT_PIT_NTF 0
61
+ ATC_RAT_PIT_P 0.135000
62
+ ATC_RAT_PIT_PDMX 0.000000
63
+ ATC_RAT_PIT_SMAX 0.000000
64
+ ATC_RAT_RLL_D 0.003600
65
+ ATC_RAT_RLL_D_FF 0.000000
66
+ ATC_RAT_RLL_FF 0.000000
67
+ ATC_RAT_RLL_FLTD 20.000000
68
+ ATC_RAT_RLL_FLTE 0.000000
69
+ ATC_RAT_RLL_FLTT 20.000000
70
+ ATC_RAT_RLL_I 0.135000
71
+ ATC_RAT_RLL_IMAX 0.500000
72
+ ATC_RAT_RLL_NEF 0
73
+ ATC_RAT_RLL_NTF 0
74
+ ATC_RAT_RLL_P 0.135000
75
+ ATC_RAT_RLL_PDMX 0.000000
76
+ ATC_RAT_RLL_SMAX 0.000000
77
+ ATC_RAT_YAW_D 0.000000
78
+ ATC_RAT_YAW_D_FF 0.000000
79
+ ATC_RAT_YAW_FF 0.000000
80
+ ATC_RAT_YAW_FLTD 20.000000
81
+ ATC_RAT_YAW_FLTE 2.500000
82
+ ATC_RAT_YAW_FLTT 20.000000
83
+ ATC_RAT_YAW_I 0.020000
84
+ ATC_RAT_YAW_IMAX 0.500000
85
+ ATC_RAT_YAW_NEF 0
86
+ ATC_RAT_YAW_NTF 0
87
+ ATC_RAT_YAW_P 0.300000
88
+ ATC_RAT_YAW_PDMX 0.000000
89
+ ATC_RAT_YAW_SMAX 0.000000
90
+ ATC_SLEW_YAW 6000.000000
91
+ ATC_THR_G_BOOST 0.000000
92
+ ATC_THR_MIX_MAN 0.100000
93
+ ATC_THR_MIX_MAX 0.500000
94
+ ATC_THR_MIX_MIN 0.100000
95
+ AUTOTUNE_AGGR 0.075000
96
+ AUTOTUNE_AXES 7
97
+ AUTOTUNE_MIN_D 0.000500
98
+ AUTO_OPTIONS 0
99
+ AVD_ENABLE 0
100
+ AVOID_ACCEL_MAX 3.000000
101
+ AVOID_ALT_MIN 0.000000
102
+ AVOID_ANGLE_MAX 1000
103
+ AVOID_BACKUP_DZ 0.100000
104
+ AVOID_BACKUP_SPD 0.750000
105
+ AVOID_BACKZ_SPD 0.750000
106
+ AVOID_BEHAVE 0
107
+ AVOID_DIST_MAX 5.000000
108
+ AVOID_ENABLE 3
109
+ AVOID_MARGIN 2.000000
110
+ BARO1_DEVID 65540
111
+ BARO1_GND_PRESS 94502.828125
112
+ BARO1_WCF_ENABLE 0
113
+ BARO2_DEVID 65796
114
+ BARO2_GND_PRESS 94504.796875
115
+ BARO2_WCF_ENABLE 0
116
+ BARO3_DEVID 0
117
+ BARO3_GND_PRESS 0.000000
118
+ BARO3_WCF_ENABLE 0
119
+ BARO_ALTERR_MAX 2000.000000
120
+ BARO_ALT_OFFSET 0.000000
121
+ BARO_EXT_BUS -1
122
+ BARO_FIELD_ELV 0.000000
123
+ BARO_FLTR_RNG 0
124
+ BARO_GND_TEMP 0.000000
125
+ BARO_OPTIONS 0
126
+ BARO_PRIMARY 0
127
+ BARO_PROBE_EXT 0
128
+ BATT2_MONITOR 0
129
+ BATT3_MONITOR 0
130
+ BATT4_MONITOR 0
131
+ BATT5_MONITOR 0
132
+ BATT6_MONITOR 0
133
+ BATT7_MONITOR 0
134
+ BATT8_MONITOR 0
135
+ BATT9_MONITOR 0
136
+ BATT_AMP_OFFSET 0.000000
137
+ BATT_AMP_PERVLT 17.000000
138
+ BATT_ARM_MAH 0
139
+ BATT_ARM_VOLT 0.000000
140
+ BATT_CAPACITY 3300
141
+ BATT_CRT_MAH 0.000000
142
+ BATT_CRT_VOLT 0.000000
143
+ BATT_CURR_PIN 12
144
+ BATT_FS_CRT_ACT 0
145
+ BATT_FS_LOW_ACT 0
146
+ BATT_FS_VOLTSRC 0
147
+ BATT_LOW_MAH 0.000000
148
+ BATT_LOW_TIMER 10
149
+ BATT_LOW_VOLT 10.500000
150
+ BATT_MONITOR 4
151
+ BATT_OPTIONS 0
152
+ BATT_SERIAL_NUM -1
153
+ BATT_VLT_OFFSET 0.000000
154
+ BATT_VOLT_MULT 10.100000
155
+ BATT_VOLT_PIN 13
156
+ BCN_TYPE 0
157
+ BRD_BOOT_DELAY 0
158
+ BRD_OPTIONS 0
159
+ BRD_RTC_TYPES 1
160
+ BRD_RTC_TZ_MIN 0
161
+ BRD_SAFETYOPTION 3
162
+ BRD_SAFETY_DEFLT 0
163
+ BRD_SAFETY_MASK 16368
164
+ BRD_SD_FENCE 0
165
+ BRD_SD_MISSION 0
166
+ BRD_SERIAL_NUM 0
167
+ BRD_VBUS_MIN 4.300000
168
+ BRD_VSERVO_MIN 0.000000
169
+ BTN_ENABLE 0
170
+ CAM1_TYPE 0
171
+ CAM2_TYPE 0
172
+ CAM_AUTO_ONLY 0
173
+ CAM_MAX_ROLL 0
174
+ CAN_D1_PROTOCOL 1
175
+ CAN_D1_PROTOCOL2 0
176
+ CAN_D2_PROTOCOL 1
177
+ CAN_D2_PROTOCOL2 0
178
+ CAN_LOGLEVEL 0
179
+ CAN_P1_DRIVER 0
180
+ CAN_P2_DRIVER 0
181
+ CC_TYPE 0
182
+ CHUTE_ENABLED 0
183
+ CIRCLE_OPTIONS 1
184
+ CIRCLE_RADIUS 1000.000000
185
+ CIRCLE_RATE 20.000000
186
+ COMPASS_AUTODEC 1
187
+ COMPASS_AUTO_ROT 2
188
+ COMPASS_CAL_FIT 16.000000
189
+ COMPASS_DEC 0.000000
190
+ COMPASS_DEV_ID 97539
191
+ COMPASS_DEV_ID2 131874
192
+ COMPASS_DEV_ID3 263178
193
+ COMPASS_DEV_ID4 97283
194
+ COMPASS_DEV_ID5 97795
195
+ COMPASS_DEV_ID6 98051
196
+ COMPASS_DEV_ID7 0
197
+ COMPASS_DEV_ID8 0
198
+ COMPASS_DIA2_X 1.000000
199
+ COMPASS_DIA2_Y 1.000000
200
+ COMPASS_DIA2_Z 1.000000
201
+ COMPASS_DIA3_X 1.000000
202
+ COMPASS_DIA3_Y 1.000000
203
+ COMPASS_DIA3_Z 1.000000
204
+ COMPASS_DIA_X 1.000000
205
+ COMPASS_DIA_Y 1.000000
206
+ COMPASS_DIA_Z 1.000000
207
+ COMPASS_DISBLMSK 0
208
+ COMPASS_ENABLE 1
209
+ COMPASS_EXTERN2 0
210
+ COMPASS_EXTERN3 0
211
+ COMPASS_EXTERNAL 1
212
+ COMPASS_FLTR_RNG 0
213
+ COMPASS_LEARN 0
214
+ COMPASS_MOT2_X 0.000000
215
+ COMPASS_MOT2_Y 0.000000
216
+ COMPASS_MOT2_Z 0.000000
217
+ COMPASS_MOT3_X 0.000000
218
+ COMPASS_MOT3_Y 0.000000
219
+ COMPASS_MOT3_Z 0.000000
220
+ COMPASS_MOTCT 0
221
+ COMPASS_MOT_X 0.000000
222
+ COMPASS_MOT_Y 0.000000
223
+ COMPASS_MOT_Z 0.000000
224
+ COMPASS_ODI2_X 0.000000
225
+ COMPASS_ODI2_Y 0.000000
226
+ COMPASS_ODI2_Z 0.000000
227
+ COMPASS_ODI3_X 0.000000
228
+ COMPASS_ODI3_Y 0.000000
229
+ COMPASS_ODI3_Z 0.000000
230
+ COMPASS_ODI_X 0.000000
231
+ COMPASS_ODI_Y 0.000000
232
+ COMPASS_ODI_Z 0.000000
233
+ COMPASS_OFFS_MAX 1800
234
+ COMPASS_OFS2_X 5.000000
235
+ COMPASS_OFS2_Y 13.000000
236
+ COMPASS_OFS2_Z -18.000000
237
+ COMPASS_OFS3_X 5.000000
238
+ COMPASS_OFS3_Y 13.000000
239
+ COMPASS_OFS3_Z -18.000000
240
+ COMPASS_OFS_X 5.000000
241
+ COMPASS_OFS_Y 13.000000
242
+ COMPASS_OFS_Z -18.000000
243
+ COMPASS_OPTIONS 0
244
+ COMPASS_ORIENT 0
245
+ COMPASS_ORIENT2 0
246
+ COMPASS_ORIENT3 0
247
+ COMPASS_PMOT_EN 0
248
+ COMPASS_PRIO1_ID 97539
249
+ COMPASS_PRIO2_ID 131874
250
+ COMPASS_PRIO3_ID 263178
251
+ COMPASS_SCALE 1.000000
252
+ COMPASS_SCALE2 1.000000
253
+ COMPASS_SCALE3 1.000000
254
+ COMPASS_USE 1
255
+ COMPASS_USE2 1
256
+ COMPASS_USE3 1
257
+ CUST_ROT_ENABLE 0
258
+ DEV_OPTIONS 0
259
+ DID_ENABLE 0
260
+ DISARM_DELAY 10
261
+ EAHRS_TYPE 0
262
+ EFI_TYPE 0
263
+ EK2_ENABLE 0
264
+ EK3_ABIAS_P_NSE 0.020000
265
+ EK3_ACC_BIAS_LIM 1.000000
266
+ EK3_ACC_P_NSE 0.350000
267
+ EK3_AFFINITY 0
268
+ EK3_ALT_M_NSE 2.000000
269
+ EK3_BCN_DELAY 50
270
+ EK3_BCN_I_GTE 500
271
+ EK3_BCN_M_NSE 1.000000
272
+ EK3_BETA_MASK 0
273
+ EK3_CHECK_SCALE 100
274
+ EK3_DRAG_BCOEF_X 0.000000
275
+ EK3_DRAG_BCOEF_Y 0.000000
276
+ EK3_DRAG_MCOEF 0.000000
277
+ EK3_DRAG_M_NSE 0.500000
278
+ EK3_EAS_I_GATE 400
279
+ EK3_EAS_M_NSE 1.400000
280
+ EK3_ENABLE 1
281
+ EK3_ERR_THRESH 0.200000
282
+ EK3_FLOW_DELAY 10
283
+ EK3_FLOW_I_GATE 300
284
+ EK3_FLOW_M_NSE 0.250000
285
+ EK3_FLOW_USE 1
286
+ EK3_GBIAS_P_NSE 0.001000
287
+ EK3_GLITCH_RAD 25
288
+ EK3_GND_EFF_DZ 4.000000
289
+ EK3_GPS_CHECK 31
290
+ EK3_GPS_VACC_MAX 0.000000
291
+ EK3_GSF_RST_MAX 2
292
+ EK3_GSF_RUN_MASK 3
293
+ EK3_GSF_USE_MASK 3
294
+ EK3_GYRO_P_NSE 0.015000
295
+ EK3_HGT_DELAY 60
296
+ EK3_HGT_I_GATE 500
297
+ EK3_HRT_FILT 2.000000
298
+ EK3_IMU_MASK 3
299
+ EK3_LOG_LEVEL 0
300
+ EK3_MAGB_P_NSE 0.000100
301
+ EK3_MAGE_P_NSE 0.001000
302
+ EK3_MAG_CAL 3
303
+ EK3_MAG_EF_LIM 50
304
+ EK3_MAG_I_GATE 300
305
+ EK3_MAG_MASK 0
306
+ EK3_MAG_M_NSE 0.050000
307
+ EK3_MAX_FLOW 2.500000
308
+ EK3_NOAID_M_NSE 10.000000
309
+ EK3_OGNM_TEST_SF 2.000000
310
+ EK3_OGN_HGT_MASK 0
311
+ EK3_OPTIONS 0
312
+ EK3_POSNE_M_NSE 0.500000
313
+ EK3_POS_I_GATE 500
314
+ EK3_PRIMARY 0
315
+ EK3_RNG_I_GATE 500
316
+ EK3_RNG_M_NSE 0.500000
317
+ EK3_RNG_USE_HGT -1
318
+ EK3_RNG_USE_SPD 2.000000
319
+ EK3_SRC1_POSXY 3
320
+ EK3_SRC1_POSZ 1
321
+ EK3_SRC1_VELXY 3
322
+ EK3_SRC1_VELZ 3
323
+ EK3_SRC1_YAW 1
324
+ EK3_SRC2_POSXY 0
325
+ EK3_SRC2_POSZ 1
326
+ EK3_SRC2_VELXY 0
327
+ EK3_SRC2_VELZ 0
328
+ EK3_SRC2_YAW 0
329
+ EK3_SRC3_POSXY 0
330
+ EK3_SRC3_POSZ 1
331
+ EK3_SRC3_VELXY 0
332
+ EK3_SRC3_VELZ 0
333
+ EK3_SRC3_YAW 0
334
+ EK3_SRC_OPTIONS 1
335
+ EK3_TAU_OUTPUT 25
336
+ EK3_TERR_GRAD 0.100000
337
+ EK3_VELD_M_NSE 0.500000
338
+ EK3_VELNE_M_NSE 0.300000
339
+ EK3_VEL_I_GATE 500
340
+ EK3_VIS_VERR_MAX 0.900000
341
+ EK3_VIS_VERR_MIN 0.100000
342
+ EK3_WENC_VERR 0.100000
343
+ EK3_WIND_PSCALE 1.000000
344
+ EK3_WIND_P_NSE 0.200000
345
+ EK3_YAW_I_GATE 300
346
+ EK3_YAW_M_NSE 0.500000
347
+ ESC_CALIBRATION 0
348
+ ESC_TLM_MAV_OFS 0
349
+ FENCE_ACTION 1
350
+ FENCE_ALT_MAX 100.000000
351
+ FENCE_ALT_MIN -10.000000
352
+ FENCE_AUTOENABLE 0
353
+ FENCE_ENABLE 0
354
+ FENCE_MARGIN 2.000000
355
+ FENCE_NTF_FREQ 1.000000
356
+ FENCE_OPTIONS 0
357
+ FENCE_RADIUS 150.000000
358
+ FENCE_TOTAL 0
359
+ FENCE_TYPE 7
360
+ FFT_ENABLE 0
361
+ FHLD_BRAKE_RATE 8
362
+ FHLD_FILT_HZ 5.000000
363
+ FHLD_FLOW_MAX 0.600000
364
+ FHLD_QUAL_MIN 10
365
+ FHLD_XY_FILT_HZ 5.000000
366
+ FHLD_XY_I 0.300000
367
+ FHLD_XY_IMAX 3000.000000
368
+ FHLD_XY_P 0.200000
369
+ FILT1_TYPE 0
370
+ FILT2_TYPE 0
371
+ FILT3_TYPE 0
372
+ FILT4_TYPE 0
373
+ FILT5_TYPE 0
374
+ FILT6_TYPE 0
375
+ FILT7_TYPE 0
376
+ FILT8_TYPE 0
377
+ FLIGHT_OPTIONS 0
378
+ FLOW_TYPE 0
379
+ FLTMODE1 7
380
+ FLTMODE2 9
381
+ FLTMODE3 6
382
+ FLTMODE4 3
383
+ FLTMODE5 5
384
+ FLTMODE6 0
385
+ FLTMODE_CH 5
386
+ FLTMODE_GCSBLOCK 0
387
+ FOLL_ENABLE 0
388
+ FORMAT_VERSION 120
389
+ FRAME_CLASS 1
390
+ FRAME_TYPE 0
391
+ FRSKY_DNLINK1_ID 20
392
+ FRSKY_DNLINK2_ID 7
393
+ FRSKY_DNLINK_ID 27
394
+ FRSKY_OPTIONS 0
395
+ FRSKY_UPLINK_ID 13
396
+ FSTRATE_DIV 1
397
+ FSTRATE_ENABLE 0
398
+ FS_CRASH_CHECK 1
399
+ FS_DR_ENABLE 2
400
+ FS_DR_TIMEOUT 30
401
+ FS_EKF_ACTION 1
402
+ FS_EKF_FILT 5.000000
403
+ FS_EKF_THRESH 0.800000
404
+ FS_GCS_ENABLE 0
405
+ FS_GCS_TIMEOUT 5.000000
406
+ FS_OPTIONS 16
407
+ FS_THR_ENABLE 1
408
+ FS_THR_VALUE 975
409
+ FS_VIBE_ENABLE 1
410
+ GCS_PID_MASK 0
411
+ GEN_TYPE 0
412
+ GND_EFFECT_COMP 1
413
+ GPS1_CAN_NODEID 0
414
+ GPS1_CAN_OVRIDE 0
415
+ GPS1_COM_PORT 1
416
+ GPS1_DELAY_MS 0
417
+ GPS1_GNSS_MODE 0
418
+ GPS1_MB_TYPE 0
419
+ GPS1_POS_X 0.000000
420
+ GPS1_POS_Y 0.000000
421
+ GPS1_POS_Z 0.000000
422
+ GPS1_RATE_MS 200
423
+ GPS1_TYPE 1
424
+ GPS2_TYPE 0
425
+ GPS_AUTO_CONFIG 1
426
+ GPS_AUTO_SWITCH 1
427
+ GPS_BLEND_MASK 5
428
+ GPS_DRV_OPTIONS 0
429
+ GPS_HDOP_GOOD 140
430
+ GPS_INJECT_TO 127
431
+ GPS_MIN_ELEV -100
432
+ GPS_NAVFILTER 8
433
+ GPS_PRIMARY 0
434
+ GPS_RAW_DATA 0
435
+ GPS_SAVE_CFG 2
436
+ GPS_SBAS_MODE 2
437
+ GPS_SBP_LOGMASK -256
438
+ GRIP_ENABLE 0
439
+ GUID_OPTIONS 0
440
+ GUID_TIMEOUT 3.000000
441
+ INITIAL_MODE 0
442
+ INS_ACC1_CALTEMP -300.000000
443
+ INS_ACC2OFFS_X 0.001000
444
+ INS_ACC2OFFS_Y 0.001000
445
+ INS_ACC2OFFS_Z 0.001000
446
+ INS_ACC2SCAL_X 1.001000
447
+ INS_ACC2SCAL_Y 1.001000
448
+ INS_ACC2SCAL_Z 1.001000
449
+ INS_ACC2_CALTEMP -300.000000
450
+ INS_ACC2_ID 0
451
+ INS_ACC3OFFS_X 0.000000
452
+ INS_ACC3OFFS_Y 0.000000
453
+ INS_ACC3OFFS_Z 0.000000
454
+ INS_ACC3SCAL_X 1.000000
455
+ INS_ACC3SCAL_Y 1.000000
456
+ INS_ACC3SCAL_Z 1.000000
457
+ INS_ACC3_CALTEMP -300.000000
458
+ INS_ACC3_ID 0
459
+ INS_ACCEL_FILTER 20
460
+ INS_ACCOFFS_X 0.001000
461
+ INS_ACCOFFS_Y 0.001000
462
+ INS_ACCOFFS_Z 0.001000
463
+ INS_ACCSCAL_X 1.001000
464
+ INS_ACCSCAL_Y 1.001000
465
+ INS_ACCSCAL_Z 1.001000
466
+ INS_ACC_BODYFIX 2
467
+ INS_ACC_ID 0
468
+ INS_ENABLE_MASK 127
469
+ INS_FAST_SAMPLE 1
470
+ INS_GYR1_CALTEMP -300.000000
471
+ INS_GYR2OFFS_X 0.000000
472
+ INS_GYR2OFFS_Y 0.000000
473
+ INS_GYR2OFFS_Z 0.000000
474
+ INS_GYR2_CALTEMP -300.000000
475
+ INS_GYR2_ID 0
476
+ INS_GYR3OFFS_X 0.000000
477
+ INS_GYR3OFFS_Y 0.000000
478
+ INS_GYR3OFFS_Z 0.000000
479
+ INS_GYR3_CALTEMP -300.000000
480
+ INS_GYR3_ID 0
481
+ INS_GYROFFS_X 0.000000
482
+ INS_GYROFFS_Y 0.000000
483
+ INS_GYROFFS_Z 0.000000
484
+ INS_GYRO_FILTER 20
485
+ INS_GYRO_RATE 0
486
+ INS_GYR_CAL 1
487
+ INS_GYR_ID 0
488
+ INS_HNTC2_ENABLE 0
489
+ INS_HNTCH_ENABLE 0
490
+ INS_LOG_BAT_CNT 1024
491
+ INS_LOG_BAT_LGCT 32
492
+ INS_LOG_BAT_LGIN 20
493
+ INS_LOG_BAT_MASK 0
494
+ INS_LOG_BAT_OPT 0
495
+ INS_POS1_X 0.000000
496
+ INS_POS1_Y 0.000000
497
+ INS_POS1_Z 0.000000
498
+ INS_POS2_X 0.000000
499
+ INS_POS2_Y 0.000000
500
+ INS_POS2_Z 0.000000
501
+ INS_POS3_X 0.000000
502
+ INS_POS3_Y 0.000000
503
+ INS_POS3_Z 0.000000
504
+ INS_RAW_LOG_OPT 0
505
+ INS_STILL_THRESH 2.500000
506
+ INS_TCAL1_ENABLE 0
507
+ INS_TCAL2_ENABLE 0
508
+ INS_TCAL3_ENABLE 0
509
+ INS_TCAL_OPTIONS 0
510
+ INS_TRIM_OPTION 1
511
+ INS_USE 1
512
+ INS_USE2 1
513
+ INS_USE3 1
514
+ KDE_NPOLE 14
515
+ LAND_ALT_LOW 1000
516
+ LAND_REPOSITION 1
517
+ LAND_SPEED 50
518
+ LAND_SPEED_HIGH 0
519
+ LGR_ENABLE 0
520
+ LOG_BACKEND_TYPE 1
521
+ LOG_BITMASK 180222
522
+ LOG_BLK_RATEMAX 0.000000
523
+ LOG_DARM_RATEMAX 0.000000
524
+ LOG_DISARMED 0
525
+ LOG_FILE_BUFSIZE 200
526
+ LOG_FILE_DSRMROT 0
527
+ LOG_FILE_MB_FREE 500
528
+ LOG_FILE_RATEMAX 0.000000
529
+ LOG_FILE_TIMEOUT 5
530
+ LOG_MAV_BUFSIZE 8
531
+ LOG_MAV_RATEMAX 0.000000
532
+ LOG_MAX_FILES 500
533
+ LOG_REPLAY 0
534
+ LOIT_ACC_MAX 500.000000
535
+ LOIT_ANG_MAX 0.000000
536
+ LOIT_BRK_ACCEL 250.000000
537
+ LOIT_BRK_DELAY 1.000000
538
+ LOIT_BRK_JERK 500.000000
539
+ LOIT_SPEED 1250.000000
540
+ MAV1_ADSB 0
541
+ MAV1_EXTRA1 0
542
+ MAV1_EXTRA2 0
543
+ MAV1_EXTRA3 0
544
+ MAV1_EXT_STAT 0
545
+ MAV1_PARAMS 0
546
+ MAV1_POSITION 0
547
+ MAV1_RAW_CTRL 0
548
+ MAV1_RAW_SENS 0
549
+ MAV1_RC_CHAN 0
550
+ MAV2_ADSB 0
551
+ MAV2_EXTRA1 0
552
+ MAV2_EXTRA2 0
553
+ MAV2_EXTRA3 0
554
+ MAV2_EXT_STAT 0
555
+ MAV2_PARAMS 0
556
+ MAV2_POSITION 0
557
+ MAV2_RAW_CTRL 0
558
+ MAV2_RAW_SENS 0
559
+ MAV2_RC_CHAN 0
560
+ MAV3_ADSB 0
561
+ MAV3_EXTRA1 0
562
+ MAV3_EXTRA2 0
563
+ MAV3_EXTRA3 0
564
+ MAV3_EXT_STAT 0
565
+ MAV3_PARAMS 0
566
+ MAV3_POSITION 0
567
+ MAV3_RAW_CTRL 0
568
+ MAV3_RAW_SENS 0
569
+ MAV3_RC_CHAN 0
570
+ MAV_GCS_SYSID 255
571
+ MAV_OPTIONS 0
572
+ MAV_SYSID 1
573
+ MAV_TELEM_DELAY 0
574
+ MIS_OPTIONS 0
575
+ MIS_RESTART 0
576
+ MIS_TOTAL 0
577
+ MNT1_TYPE 0
578
+ MNT2_TYPE 0
579
+ MOT_BAT_CURR_MAX 0.000000
580
+ MOT_BAT_CURR_TC 5.000000
581
+ MOT_BAT_IDX 0
582
+ MOT_BAT_VOLT_MAX 12.800000
583
+ MOT_BAT_VOLT_MIN 9.600000
584
+ MOT_BOOST_SCALE 0.000000
585
+ MOT_HOVER_LEARN 2
586
+ MOT_OPTIONS 0
587
+ MOT_PWM_MAX 2000
588
+ MOT_PWM_MIN 1000
589
+ MOT_PWM_TYPE 0
590
+ MOT_SAFE_DISARM 0
591
+ MOT_SAFE_TIME 1.000000
592
+ MOT_SLEW_DN_TIME 0.000000
593
+ MOT_SLEW_UP_TIME 0.000000
594
+ MOT_SPIN_ARM 0.100000
595
+ MOT_SPIN_MAX 0.950000
596
+ MOT_SPIN_MIN 0.150000
597
+ MOT_SPOOL_TIME 0.500000
598
+ MOT_SPOOL_TIM_DN 0.000000
599
+ MOT_THST_EXPO 0.650000
600
+ MOT_THST_HOVER 0.390000
601
+ MOT_YAW_HEADROOM 200
602
+ MSP_OPTIONS 0
603
+ MSP_OSD_NCELLS 0
604
+ NET_ENABLE 0
605
+ NET_P1_TYPE 0
606
+ NET_P2_TYPE 0
607
+ NET_P3_TYPE 0
608
+ NET_P4_TYPE 0
609
+ NMEA_MSG_EN 3
610
+ NMEA_RATE_MS 100
611
+ NTF_BUZZ_ON_LVL 1
612
+ NTF_BUZZ_PIN -1
613
+ NTF_BUZZ_TYPES 5
614
+ NTF_BUZZ_VOLUME 100
615
+ NTF_DISPLAY_TYPE 0
616
+ NTF_LED_BRIGHT 3
617
+ NTF_LED_LEN 1
618
+ NTF_LED_OVERRIDE 0
619
+ NTF_LED_TYPES 123079
620
+ OA_TYPE 0
621
+ OSD_TYPE 0
622
+ PHLD_BRAKE_ANGLE 3000
623
+ PHLD_BRAKE_RATE 8
624
+ PILOT_ACCEL_Z 250
625
+ PILOT_SPEED_DN 0
626
+ PILOT_SPEED_UP 250
627
+ PILOT_THR_BHV 0
628
+ PILOT_THR_FILT 0.000000
629
+ PILOT_TKOFF_ALT 0.000000
630
+ PILOT_Y_EXPO 0.000000
631
+ PILOT_Y_RATE 202.500000
632
+ PILOT_Y_RATE_TC 0.000000
633
+ PLDP_DELAY 0.000000
634
+ PLDP_RNG_MAX 0.000000
635
+ PLDP_SPEED_DN 0.000000
636
+ PLDP_THRESH 0.900000
637
+ PLND_ENABLED 0
638
+ PRX1_TYPE 0
639
+ PRX2_TYPE 0
640
+ PRX3_TYPE 0
641
+ PRX4_TYPE 0
642
+ PRX5_TYPE 0
643
+ PRX_ALT_MIN 1.000000
644
+ PRX_FILT 0.250000
645
+ PRX_IGN_GND 0
646
+ PRX_LOG_RAW 0
647
+ PSC_ACCZ_D 0.000000
648
+ PSC_ACCZ_D_FF 0.000000
649
+ PSC_ACCZ_FF 0.000000
650
+ PSC_ACCZ_FLTD 0.000000
651
+ PSC_ACCZ_FLTE 20.000000
652
+ PSC_ACCZ_FLTT 0.000000
653
+ PSC_ACCZ_I 1.000000
654
+ PSC_ACCZ_IMAX 800.000000
655
+ PSC_ACCZ_NEF 0
656
+ PSC_ACCZ_NTF 0
657
+ PSC_ACCZ_P 0.500000
658
+ PSC_ACCZ_PDMX 0.000000
659
+ PSC_ACCZ_SMAX 0.000000
660
+ PSC_ANGLE_MAX 0.000000
661
+ PSC_JERK_XY 5.000000
662
+ PSC_JERK_Z 5.000000
663
+ PSC_POSXY_P 1.000000
664
+ PSC_POSZ_P 1.000000
665
+ PSC_VELXY_D 0.500000
666
+ PSC_VELXY_FF 0.000000
667
+ PSC_VELXY_FLTD 5.000000
668
+ PSC_VELXY_FLTE 5.000000
669
+ PSC_VELXY_I 1.000000
670
+ PSC_VELXY_IMAX 1000.000000
671
+ PSC_VELXY_P 2.000000
672
+ PSC_VELZ_D 0.000000
673
+ PSC_VELZ_FF 0.000000
674
+ PSC_VELZ_FLTD 5.000000
675
+ PSC_VELZ_FLTE 5.000000
676
+ PSC_VELZ_I 0.000000
677
+ PSC_VELZ_IMAX 1000.000000
678
+ PSC_VELZ_P 5.000000
679
+ RALLY_INCL_HOME 1
680
+ RALLY_LIMIT_KM 0.300000
681
+ RALLY_TOTAL 0
682
+ RC10_DZ 0
683
+ RC10_MAX 1900
684
+ RC10_MIN 1100
685
+ RC10_OPTION 0
686
+ RC10_REVERSED 0
687
+ RC10_TRIM 1500
688
+ RC11_DZ 0
689
+ RC11_MAX 1900
690
+ RC11_MIN 1100
691
+ RC11_OPTION 0
692
+ RC11_REVERSED 0
693
+ RC11_TRIM 1500
694
+ RC12_DZ 0
695
+ RC12_MAX 1900
696
+ RC12_MIN 1100
697
+ RC12_OPTION 0
698
+ RC12_REVERSED 0
699
+ RC12_TRIM 1500
700
+ RC13_DZ 0
701
+ RC13_MAX 1900
702
+ RC13_MIN 1100
703
+ RC13_OPTION 0
704
+ RC13_REVERSED 0
705
+ RC13_TRIM 1500
706
+ RC14_DZ 0
707
+ RC14_MAX 1900
708
+ RC14_MIN 1100
709
+ RC14_OPTION 0
710
+ RC14_REVERSED 0
711
+ RC14_TRIM 1500
712
+ RC15_DZ 0
713
+ RC15_MAX 1900
714
+ RC15_MIN 1100
715
+ RC15_OPTION 0
716
+ RC15_REVERSED 0
717
+ RC15_TRIM 1500
718
+ RC16_DZ 0
719
+ RC16_MAX 1900
720
+ RC16_MIN 1100
721
+ RC16_OPTION 0
722
+ RC16_REVERSED 0
723
+ RC16_TRIM 1500
724
+ RC1_DZ 20
725
+ RC1_MAX 2000
726
+ RC1_MIN 1000
727
+ RC1_OPTION 0
728
+ RC1_REVERSED 0
729
+ RC1_TRIM 1500
730
+ RC2_DZ 20
731
+ RC2_MAX 2000
732
+ RC2_MIN 1000
733
+ RC2_OPTION 0
734
+ RC2_REVERSED 0
735
+ RC2_TRIM 1500
736
+ RC3_DZ 30
737
+ RC3_MAX 2000
738
+ RC3_MIN 1000
739
+ RC3_OPTION 0
740
+ RC3_REVERSED 0
741
+ RC3_TRIM 1500
742
+ RC4_DZ 20
743
+ RC4_MAX 2000
744
+ RC4_MIN 1000
745
+ RC4_OPTION 0
746
+ RC4_REVERSED 0
747
+ RC4_TRIM 1500
748
+ RC5_DZ 0
749
+ RC5_MAX 2000
750
+ RC5_MIN 1000
751
+ RC5_OPTION 0
752
+ RC5_REVERSED 0
753
+ RC5_TRIM 1500
754
+ RC6_DZ 0
755
+ RC6_MAX 2000
756
+ RC6_MIN 1000
757
+ RC6_OPTION 0
758
+ RC6_REVERSED 0
759
+ RC6_TRIM 1500
760
+ RC7_DZ 0
761
+ RC7_MAX 2000
762
+ RC7_MIN 1000
763
+ RC7_OPTION 7
764
+ RC7_REVERSED 0
765
+ RC7_TRIM 1500
766
+ RC8_DZ 0
767
+ RC8_MAX 2000
768
+ RC8_MIN 1000
769
+ RC8_OPTION 0
770
+ RC8_REVERSED 0
771
+ RC8_TRIM 1500
772
+ RC9_DZ 0
773
+ RC9_MAX 1900
774
+ RC9_MIN 1100
775
+ RC9_OPTION 0
776
+ RC9_REVERSED 0
777
+ RC9_TRIM 1500
778
+ RCMAP_PITCH 2
779
+ RCMAP_ROLL 1
780
+ RCMAP_THROTTLE 3
781
+ RCMAP_YAW 4
782
+ RC_FS_TIMEOUT 1.000000
783
+ RC_OPTIONS 32
784
+ RC_OVERRIDE_TIME 3.000000
785
+ RC_PROTOCOLS 1
786
+ RC_SPEED 490
787
+ RELAY1_DEFAULT 0
788
+ RELAY1_FUNCTION 1
789
+ RELAY1_INVERTED 0
790
+ RELAY1_PIN 13
791
+ RELAY2_FUNCTION 0
792
+ RELAY3_FUNCTION 0
793
+ RELAY4_FUNCTION 0
794
+ RELAY5_FUNCTION 0
795
+ RELAY6_FUNCTION 0
796
+ RNGFND1_TYPE 0
797
+ RNGFND2_TYPE 0
798
+ RNGFND3_TYPE 0
799
+ RNGFND4_TYPE 0
800
+ RNGFND5_TYPE 0
801
+ RNGFND6_TYPE 0
802
+ RNGFND7_TYPE 0
803
+ RNGFND8_TYPE 0
804
+ RNGFND9_TYPE 0
805
+ RNGFNDA_TYPE 0
806
+ RNGFND_FILT 0.500000
807
+ RPM1_TYPE 0
808
+ RPM2_TYPE 0
809
+ RSSI_TYPE 0
810
+ RTL_ALT 1500
811
+ RTL_ALT_FINAL 0
812
+ RTL_ALT_TYPE 0
813
+ RTL_CLIMB_MIN 0
814
+ RTL_CONE_SLOPE 3.000000
815
+ RTL_LOIT_TIME 5000
816
+ RTL_OPTIONS 0
817
+ RTL_SPEED 0
818
+ SCHED_DEBUG 0
819
+ SCHED_LOOP_RATE 400
820
+ SCHED_OPTIONS 0
821
+ SCR_ENABLE 0
822
+ SERIAL0_BAUD 115
823
+ SERIAL0_PROTOCOL 2
824
+ SERIAL1_BAUD 57
825
+ SERIAL1_OPTIONS 0
826
+ SERIAL1_PROTOCOL 2
827
+ SERIAL2_BAUD 57
828
+ SERIAL2_OPTIONS 0
829
+ SERIAL2_PROTOCOL 2
830
+ SERIAL3_BAUD 230
831
+ SERIAL3_OPTIONS 0
832
+ SERIAL3_PROTOCOL 5
833
+ SERIAL4_BAUD 230
834
+ SERIAL4_OPTIONS 0
835
+ SERIAL4_PROTOCOL 5
836
+ SERIAL5_BAUD 57
837
+ SERIAL5_OPTIONS 0
838
+ SERIAL5_PROTOCOL -1
839
+ SERIAL6_BAUD 57
840
+ SERIAL6_OPTIONS 0
841
+ SERIAL6_PROTOCOL -1
842
+ SERIAL7_BAUD 57
843
+ SERIAL7_OPTIONS 0
844
+ SERIAL7_PROTOCOL -1
845
+ SERIAL_PASS1 0
846
+ SERIAL_PASS2 -1
847
+ SERIAL_PASSTIMO 15
848
+ SERVO10_FUNCTION 0
849
+ SERVO10_MAX 1900
850
+ SERVO10_MIN 1100
851
+ SERVO10_REVERSED 0
852
+ SERVO10_TRIM 1500
853
+ SERVO11_FUNCTION 0
854
+ SERVO11_MAX 1900
855
+ SERVO11_MIN 1100
856
+ SERVO11_REVERSED 0
857
+ SERVO11_TRIM 1500
858
+ SERVO12_FUNCTION 0
859
+ SERVO12_MAX 1900
860
+ SERVO12_MIN 1100
861
+ SERVO12_REVERSED 0
862
+ SERVO12_TRIM 1500
863
+ SERVO13_FUNCTION 0
864
+ SERVO13_MAX 1900
865
+ SERVO13_MIN 1100
866
+ SERVO13_REVERSED 0
867
+ SERVO13_TRIM 1500
868
+ SERVO14_FUNCTION 0
869
+ SERVO14_MAX 1900
870
+ SERVO14_MIN 1100
871
+ SERVO14_REVERSED 0
872
+ SERVO14_TRIM 1500
873
+ SERVO15_FUNCTION 0
874
+ SERVO15_MAX 1900
875
+ SERVO15_MIN 1100
876
+ SERVO15_REVERSED 0
877
+ SERVO15_TRIM 1500
878
+ SERVO16_FUNCTION 0
879
+ SERVO16_MAX 1900
880
+ SERVO16_MIN 1100
881
+ SERVO16_REVERSED 0
882
+ SERVO16_TRIM 1500
883
+ SERVO1_FUNCTION 33
884
+ SERVO1_MAX 1900
885
+ SERVO1_MIN 1100
886
+ SERVO1_REVERSED 0
887
+ SERVO1_TRIM 1500
888
+ SERVO2_FUNCTION 34
889
+ SERVO2_MAX 1900
890
+ SERVO2_MIN 1100
891
+ SERVO2_REVERSED 0
892
+ SERVO2_TRIM 1500
893
+ SERVO3_FUNCTION 35
894
+ SERVO3_MAX 1900
895
+ SERVO3_MIN 1100
896
+ SERVO3_REVERSED 0
897
+ SERVO3_TRIM 1500
898
+ SERVO4_FUNCTION 36
899
+ SERVO4_MAX 1900
900
+ SERVO4_MIN 1100
901
+ SERVO4_REVERSED 0
902
+ SERVO4_TRIM 1500
903
+ SERVO5_FUNCTION 0
904
+ SERVO5_MAX 1900
905
+ SERVO5_MIN 1100
906
+ SERVO5_REVERSED 0
907
+ SERVO5_TRIM 1500
908
+ SERVO6_FUNCTION 0
909
+ SERVO6_MAX 1900
910
+ SERVO6_MIN 1100
911
+ SERVO6_REVERSED 0
912
+ SERVO6_TRIM 1500
913
+ SERVO7_FUNCTION 0
914
+ SERVO7_MAX 1900
915
+ SERVO7_MIN 1100
916
+ SERVO7_REVERSED 0
917
+ SERVO7_TRIM 1500
918
+ SERVO8_FUNCTION 0
919
+ SERVO8_MAX 1900
920
+ SERVO8_MIN 1100
921
+ SERVO8_REVERSED 0
922
+ SERVO8_TRIM 1500
923
+ SERVO9_FUNCTION 0
924
+ SERVO9_MAX 1900
925
+ SERVO9_MIN 1100
926
+ SERVO9_REVERSED 0
927
+ SERVO9_TRIM 1500
928
+ SERVO_32_ENABLE 0
929
+ SERVO_DSHOT_ESC 0
930
+ SERVO_DSHOT_RATE 0
931
+ SERVO_FTW_MASK 0
932
+ SERVO_FTW_POLES 14
933
+ SERVO_FTW_RVMASK 0
934
+ SERVO_GPIO_MASK 0
935
+ SERVO_RATE 50
936
+ SERVO_RC_FS_MSK 0
937
+ SERVO_ROB_POSMAX 4095
938
+ SERVO_ROB_POSMIN 0
939
+ SERVO_SBUS_RATE 50
940
+ SERVO_VOLZ_MASK 0
941
+ SERVO_VOLZ_RANGE 200
942
+ SID_AXIS 0
943
+ SIMPLE 0
944
+ SIM_ACC1_BIAS_X 0.000000
945
+ SIM_ACC1_BIAS_Y 0.000000
946
+ SIM_ACC1_BIAS_Z 0.000000
947
+ SIM_ACC1_RND 0.000000
948
+ SIM_ACC1_SCAL_X 0.000000
949
+ SIM_ACC1_SCAL_Y 0.000000
950
+ SIM_ACC1_SCAL_Z 0.000000
951
+ SIM_ACC2_BIAS_X 0.000000
952
+ SIM_ACC2_BIAS_Y 0.000000
953
+ SIM_ACC2_BIAS_Z 0.000000
954
+ SIM_ACC2_RND 0.000000
955
+ SIM_ACC2_SCAL_X 0.000000
956
+ SIM_ACC2_SCAL_Y 0.000000
957
+ SIM_ACC2_SCAL_Z 0.000000
958
+ SIM_ACC3_BIAS_X 0.000000
959
+ SIM_ACC3_BIAS_Y 0.000000
960
+ SIM_ACC3_BIAS_Z 0.000000
961
+ SIM_ACC3_RND 0.000000
962
+ SIM_ACC3_SCAL_X 0.000000
963
+ SIM_ACC3_SCAL_Y 0.000000
964
+ SIM_ACC3_SCAL_Z 0.000000
965
+ SIM_ACCEL1_FAIL 0.000000
966
+ SIM_ACCEL2_FAIL 0.000000
967
+ SIM_ACCEL3_FAIL 0.000000
968
+ SIM_ACC_FAIL_MSK 0
969
+ SIM_ACC_FILE_RW 0
970
+ SIM_ACC_TRIM_X 0.000000
971
+ SIM_ACC_TRIM_Y 0.000000
972
+ SIM_ACC_TRIM_Z 0.000000
973
+ SIM_ADSB_ALT 1000.000000
974
+ SIM_ADSB_COUNT -1
975
+ SIM_ADSB_RADIUS 10000.000000
976
+ SIM_ADSB_TX 0
977
+ SIM_ADSB_TYPES 1
978
+ SIM_ARSPD2_FAIL 0.000000
979
+ SIM_ARSPD2_FAILP 0.000000
980
+ SIM_ARSPD2_OFS 2013.000000
981
+ SIM_ARSPD2_PITOT 0.000000
982
+ SIM_ARSPD2_RATIO 1.990000
983
+ SIM_ARSPD2_RND 2.000000
984
+ SIM_ARSPD2_SIGN 0
985
+ SIM_ARSPD_FAIL 0.000000
986
+ SIM_ARSPD_FAILP 0.000000
987
+ SIM_ARSPD_OFS 2013.000000
988
+ SIM_ARSPD_PITOT 0.000000
989
+ SIM_ARSPD_RATIO 1.990000
990
+ SIM_ARSPD_RND 2.000000
991
+ SIM_ARSPD_SIGN 0
992
+ SIM_BAR2_DELAY 0
993
+ SIM_BAR2_DISABLE 0
994
+ SIM_BAR2_DRIFT 0.000000
995
+ SIM_BAR2_FREEZE 0
996
+ SIM_BAR2_GLITCH 0.000000
997
+ SIM_BAR2_RND 0.200000
998
+ SIM_BAR2_WCF_BAK 0.000000
999
+ SIM_BAR2_WCF_DN 0.000000
1000
+ SIM_BAR2_WCF_FWD 0.000000
1001
+ SIM_BAR2_WCF_LFT 0.000000
1002
+ SIM_BAR2_WCF_RGT 0.000000
1003
+ SIM_BAR2_WCF_UP 0.000000
1004
+ SIM_BAR3_DELAY 0
1005
+ SIM_BAR3_DISABLE 0
1006
+ SIM_BAR3_DRIFT 0.000000
1007
+ SIM_BAR3_FREEZE 0
1008
+ SIM_BAR3_GLITCH 0.000000
1009
+ SIM_BAR3_RND 0.200000
1010
+ SIM_BAR3_WCF_BAK 0.000000
1011
+ SIM_BAR3_WCF_DN 0.000000
1012
+ SIM_BAR3_WCF_FWD 0.000000
1013
+ SIM_BAR3_WCF_LFT 0.000000
1014
+ SIM_BAR3_WCF_RGT 0.000000
1015
+ SIM_BAR3_WCF_UP 0.000000
1016
+ SIM_BARO_COUNT 2
1017
+ SIM_BARO_DELAY 0
1018
+ SIM_BARO_DISABLE 0
1019
+ SIM_BARO_DRIFT 0.000000
1020
+ SIM_BARO_FREEZE 0
1021
+ SIM_BARO_GLITCH 0.000000
1022
+ SIM_BARO_RND 0.000000
1023
+ SIM_BARO_WCF_BAK 0.000000
1024
+ SIM_BARO_WCF_DN 0.000000
1025
+ SIM_BARO_WCF_FWD 0.000000
1026
+ SIM_BARO_WCF_LFT 0.000000
1027
+ SIM_BARO_WCF_RGT 0.000000
1028
+ SIM_BARO_WCF_UP 0.000000
1029
+ SIM_BATT_CAP_AH 0.000000
1030
+ SIM_BATT_VOLTAGE 12.600000
1031
+ SIM_BAUDLIMIT_EN 0
1032
+ SIM_CAN_SRV_MSK 0
1033
+ SIM_CAN_TYPE1 1
1034
+ SIM_CAN_TYPE2 1
1035
+ SIM_CLAMP_CH 0
1036
+ SIM_DRIFT_SPEED 0.050000
1037
+ SIM_DRIFT_TIME 5.000000
1038
+ SIM_EFI_TYPE 0
1039
+ SIM_ENGINE_FAIL 0
1040
+ SIM_ENGINE_MUL 0.000000
1041
+ SIM_ESC_ARM_RPM 0.000000
1042
+ SIM_ESC_TELEM 1
1043
+ SIM_FLOAT_EXCEPT 1
1044
+ SIM_FLOW_DELAY 0
1045
+ SIM_FLOW_ENABLE 0
1046
+ SIM_FLOW_POS_X 0.000000
1047
+ SIM_FLOW_POS_Y 0.000000
1048
+ SIM_FLOW_POS_Z 0.000000
1049
+ SIM_FLOW_RATE 10
1050
+ SIM_FLOW_RND 0.050000
1051
+ SIM_FTOWESC_ENA 0
1052
+ SIM_FTOWESC_POW 4095
1053
+ SIM_GND_BEHAV -1
1054
+ SIM_GPS1_ACC 0.300000
1055
+ SIM_GPS1_ALT_OFS 0
1056
+ SIM_GPS1_BYTELOS 0.000000
1057
+ SIM_GPS1_DRFTALT 0.000000
1058
+ SIM_GPS1_ENABLE 1
1059
+ SIM_GPS1_GLTCH_X 0.000000
1060
+ SIM_GPS1_GLTCH_Y 0.000000
1061
+ SIM_GPS1_GLTCH_Z 0.000000
1062
+ SIM_GPS1_HDG 0
1063
+ SIM_GPS1_HZ 5
1064
+ SIM_GPS1_JAM 0
1065
+ SIM_GPS1_LAG_MS 100
1066
+ SIM_GPS1_LCKTIME 0
1067
+ SIM_GPS1_NOISE 0.000000
1068
+ SIM_GPS1_NUMSATS 10
1069
+ SIM_GPS1_POS_X 0.000000
1070
+ SIM_GPS1_POS_Y 0.000000
1071
+ SIM_GPS1_POS_Z 0.000000
1072
+ SIM_GPS1_TYPE 1
1073
+ SIM_GPS1_VERR_X 0.000000
1074
+ SIM_GPS1_VERR_Y 0.000000
1075
+ SIM_GPS1_VERR_Z 0.000000
1076
+ SIM_GPS2_ENABLE 0
1077
+ SIM_GPS3_ENABLE 0
1078
+ SIM_GPS4_ENABLE 0
1079
+ SIM_GPS_LOG_NUM 0
1080
+ SIM_GRPE_ENABLE 0
1081
+ SIM_GRPE_PIN -1
1082
+ SIM_GRPS_ENABLE 0
1083
+ SIM_GRPS_GRAB 2000
1084
+ SIM_GRPS_PIN -1
1085
+ SIM_GRPS_RELEASE 1000
1086
+ SIM_GRPS_REVERSE 0
1087
+ SIM_GYR1_BIAS_X 0.000000
1088
+ SIM_GYR1_BIAS_Y 0.000000
1089
+ SIM_GYR1_BIAS_Z 0.000000
1090
+ SIM_GYR1_RND 0.000000
1091
+ SIM_GYR1_SCALE_X 0.000000
1092
+ SIM_GYR1_SCALE_Y 0.000000
1093
+ SIM_GYR1_SCALE_Z 0.000000
1094
+ SIM_GYR2_BIAS_X 0.000000
1095
+ SIM_GYR2_BIAS_Y 0.000000
1096
+ SIM_GYR2_BIAS_Z 0.000000
1097
+ SIM_GYR2_RND 0.000000
1098
+ SIM_GYR2_SCALE_X 0.000000
1099
+ SIM_GYR2_SCALE_Y 0.000000
1100
+ SIM_GYR2_SCALE_Z 0.000000
1101
+ SIM_GYR3_BIAS_X 0.000000
1102
+ SIM_GYR3_BIAS_Y 0.000000
1103
+ SIM_GYR3_BIAS_Z 0.000000
1104
+ SIM_GYR3_RND 0.000000
1105
+ SIM_GYR3_SCALE_X 0.000000
1106
+ SIM_GYR3_SCALE_Y 0.000000
1107
+ SIM_GYR3_SCALE_Z 0.000000
1108
+ SIM_GYR_FAIL_MSK 0
1109
+ SIM_GYR_FILE_RW 0
1110
+ SIM_IE24_ENABLE 0
1111
+ SIM_IE24_ERROR 0
1112
+ SIM_IE24_STATE -1
1113
+ SIM_IMUT1_ENABLE 0
1114
+ SIM_IMUT2_ENABLE 0
1115
+ SIM_IMUT3_ENABLE 0
1116
+ SIM_IMUT_END 45.000000
1117
+ SIM_IMUT_FIXED 0.000000
1118
+ SIM_IMUT_START 25.000000
1119
+ SIM_IMUT_TCONST 300.000000
1120
+ SIM_IMU_COUNT 2
1121
+ SIM_IMU_ORIENT 0
1122
+ SIM_IMU_POS_X 0.000000
1123
+ SIM_IMU_POS_Y 0.000000
1124
+ SIM_IMU_POS_Z 0.000000
1125
+ SIM_INIT_ALT_OFS 0.000000
1126
+ SIM_INIT_LAT_OFS 0.000000
1127
+ SIM_INIT_LON_OFS 0.000000
1128
+ SIM_INS_THR_MIN 0.100000
1129
+ SIM_JSON_MASTER 0
1130
+ SIM_LED_LAYOUT 0
1131
+ SIM_LOOP_DELAY 0
1132
+ SIM_MAG1_DEVID 97539
1133
+ SIM_MAG1_DIA_X 0.000000
1134
+ SIM_MAG1_DIA_Y 0.000000
1135
+ SIM_MAG1_DIA_Z 0.000000
1136
+ SIM_MAG1_FAIL 0
1137
+ SIM_MAG1_ODI_X 0.000000
1138
+ SIM_MAG1_ODI_Y 0.000000
1139
+ SIM_MAG1_ODI_Z 0.000000
1140
+ SIM_MAG1_OFS_X 5.000000
1141
+ SIM_MAG1_OFS_Y 13.000000
1142
+ SIM_MAG1_OFS_Z -18.000000
1143
+ SIM_MAG1_ORIENT 0
1144
+ SIM_MAG1_SCALING 1.000000
1145
+ SIM_MAG2_DEVID 131874
1146
+ SIM_MAG2_DIA_X 0.000000
1147
+ SIM_MAG2_DIA_Y 0.000000
1148
+ SIM_MAG2_DIA_Z 0.000000
1149
+ SIM_MAG2_FAIL 0
1150
+ SIM_MAG2_ODI_X 0.000000
1151
+ SIM_MAG2_ODI_Y 0.000000
1152
+ SIM_MAG2_ODI_Z 0.000000
1153
+ SIM_MAG2_OFS_X 5.000000
1154
+ SIM_MAG2_OFS_Y 13.000000
1155
+ SIM_MAG2_OFS_Z -18.000000
1156
+ SIM_MAG2_ORIENT 0
1157
+ SIM_MAG2_SCALING 1.000000
1158
+ SIM_MAG3_DEVID 263178
1159
+ SIM_MAG3_DIA_X 0.000000
1160
+ SIM_MAG3_DIA_Y 0.000000
1161
+ SIM_MAG3_DIA_Z 0.000000
1162
+ SIM_MAG3_FAIL 0
1163
+ SIM_MAG3_ODI_X 0.000000
1164
+ SIM_MAG3_ODI_Y 0.000000
1165
+ SIM_MAG3_ODI_Z 0.000000
1166
+ SIM_MAG3_OFS_X 5.000000
1167
+ SIM_MAG3_OFS_Y 13.000000
1168
+ SIM_MAG3_OFS_Z -18.000000
1169
+ SIM_MAG3_ORIENT 0
1170
+ SIM_MAG3_SCALING 1.000000
1171
+ SIM_MAG4_DEVID 97283
1172
+ SIM_MAG5_DEVID 97795
1173
+ SIM_MAG6_DEVID 98051
1174
+ SIM_MAG7_DEVID 0
1175
+ SIM_MAG8_DEVID 0
1176
+ SIM_MAG_ALY_HGT 1.000000
1177
+ SIM_MAG_ALY_X 0.000000
1178
+ SIM_MAG_ALY_Y 0.000000
1179
+ SIM_MAG_ALY_Z 0.000000
1180
+ SIM_MAG_DELAY 0
1181
+ SIM_MAG_MOT_X 0.000000
1182
+ SIM_MAG_MOT_Y 0.000000
1183
+ SIM_MAG_MOT_Z 0.000000
1184
+ SIM_MAG_RND 0.000000
1185
+ SIM_MAG_SAVE_IDS 1
1186
+ SIM_ODOM_ENABLE 0
1187
+ SIM_OH_MASK 0
1188
+ SIM_OH_RELAY_MSK -1
1189
+ SIM_OPOS_ALT 584.000000
1190
+ SIM_OPOS_HDG 353.000000
1191
+ SIM_OPOS_LAT -35.363262
1192
+ SIM_OPOS_LNG 149.165237
1193
+ SIM_PARA_ENABLE 0
1194
+ SIM_PARA_PIN -1
1195
+ SIM_PIN_MASK 0
1196
+ SIM_PLD_ALT_LMT 15.000000
1197
+ SIM_PLD_DIST_LMT 10.000000
1198
+ SIM_PLD_ENABLE 0
1199
+ SIM_PLD_HEIGHT 0.000000
1200
+ SIM_PLD_LAT 0.000000
1201
+ SIM_PLD_LON 0.000000
1202
+ SIM_PLD_OPTIONS 0
1203
+ SIM_PLD_ORIENT 24
1204
+ SIM_PLD_RATE 100
1205
+ SIM_PLD_SHIP 0
1206
+ SIM_PLD_TYPE 0
1207
+ SIM_PLD_YAW 0
1208
+ SIM_RATE_HZ 1200
1209
+ SIM_RC_CHANCOUNT 16
1210
+ SIM_RC_FAIL 0
1211
+ SIM_RICH_CTRL -1
1212
+ SIM_RICH_ENABLE 0
1213
+ SIM_SERVO_DELAY 0.000000
1214
+ SIM_SERVO_FILTER 0.000000
1215
+ SIM_SERVO_SPEED 0.140000
1216
+ SIM_SHIP_DSIZE 10.000000
1217
+ SIM_SHIP_ENABLE 0
1218
+ SIM_SHIP_OFS_X 0.000000
1219
+ SIM_SHIP_OFS_Y 0.000000
1220
+ SIM_SHIP_OFS_Z 0.000000
1221
+ SIM_SHIP_PSIZE 1000.000000
1222
+ SIM_SHIP_SPEED 3.000000
1223
+ SIM_SHIP_SYSID 17
1224
+ SIM_SHOVE_TIME 0
1225
+ SIM_SHOVE_X 0.000000
1226
+ SIM_SHOVE_Y 0.000000
1227
+ SIM_SHOVE_Z 0.000000
1228
+ SIM_SLUP_ENABLE 0
1229
+ SIM_SONAR_GLITCH 0.000000
1230
+ SIM_SONAR_POS_X 0.000000
1231
+ SIM_SONAR_POS_Y 0.000000
1232
+ SIM_SONAR_POS_Z 0.000000
1233
+ SIM_SONAR_RND 0.000000
1234
+ SIM_SONAR_ROT 25
1235
+ SIM_SONAR_SCALE 12.121200
1236
+ SIM_SPEEDUP 1.000000
1237
+ SIM_SPR_ENABLE 0
1238
+ SIM_SPR_PUMP -1
1239
+ SIM_SPR_SPIN -1
1240
+ SIM_TA_ENABLE 1
1241
+ SIM_TEMP_BFACTOR 0.000000
1242
+ SIM_TEMP_BRD_OFF 20.000000
1243
+ SIM_TEMP_START 25.000000
1244
+ SIM_TEMP_TCONST 30.000000
1245
+ SIM_TERRAIN 1
1246
+ SIM_TETH_ENABLE 0
1247
+ SIM_THML_SCENARI 0
1248
+ SIM_TIDE_DIR 0.000000
1249
+ SIM_TIDE_SPEED 0.000000
1250
+ SIM_TIME_JITTER 0
1251
+ SIM_TWIST_TIME 0
1252
+ SIM_TWIST_X 0.000000
1253
+ SIM_TWIST_Y 0.000000
1254
+ SIM_TWIST_Z 0.000000
1255
+ SIM_UART_LOSS 0.000000
1256
+ SIM_VIB_FREQ_X 0.000000
1257
+ SIM_VIB_FREQ_Y 0.000000
1258
+ SIM_VIB_FREQ_Z 0.000000
1259
+ SIM_VIB_MOT_HMNC 1
1260
+ SIM_VIB_MOT_MASK 0
1261
+ SIM_VIB_MOT_MAX 0.000000
1262
+ SIM_VIB_MOT_MULT 1.000000
1263
+ SIM_VICON_FAIL 0
1264
+ SIM_VICON_GLIT_X 0.000000
1265
+ SIM_VICON_GLIT_Y 0.000000
1266
+ SIM_VICON_GLIT_Z 0.000000
1267
+ SIM_VICON_POS_X 0.000000
1268
+ SIM_VICON_POS_Y 0.000000
1269
+ SIM_VICON_POS_Z 0.000000
1270
+ SIM_VICON_P_SD 0.000000
1271
+ SIM_VICON_RATE 50
1272
+ SIM_VICON_TMASK 3
1273
+ SIM_VICON_VGLI_X 0.000000
1274
+ SIM_VICON_VGLI_Y 0.000000
1275
+ SIM_VICON_VGLI_Z 0.000000
1276
+ SIM_VICON_V_SD 0.000000
1277
+ SIM_VICON_YAW 0
1278
+ SIM_VICON_YAWERR 0
1279
+ SIM_VOLZ_ENA 0
1280
+ SIM_VOLZ_FMASK 0
1281
+ SIM_VOLZ_MASK 11
1282
+ SIM_WAVE_AMP 0.500000
1283
+ SIM_WAVE_DIR 0.000000
1284
+ SIM_WAVE_ENABLE 0
1285
+ SIM_WAVE_LENGTH 10.000000
1286
+ SIM_WAVE_SPEED 0.500000
1287
+ SIM_WIND_DIR 180.000000
1288
+ SIM_WIND_DIR_Z 0.000000
1289
+ SIM_WIND_SPD 0.000000
1290
+ SIM_WIND_T 0
1291
+ SIM_WIND_TC 5.000000
1292
+ SIM_WIND_TURB 0.000000
1293
+ SIM_WIND_T_ALT 60.000000
1294
+ SIM_WIND_T_COEF 0.010000
1295
+ SIM_WOW_PIN -1
1296
+ SPRAY_ENABLE 0
1297
+ SRTL_ACCURACY 2.000000
1298
+ SRTL_OPTIONS 0
1299
+ SRTL_POINTS 300
1300
+ STAT_BOOTCNT 1
1301
+ STAT_FLTTIME 0
1302
+ STAT_RESET 1
1303
+ STAT_RUNTIME 0
1304
+ SUPER_SIMPLE 0
1305
+ SURFTRAK_MODE 1
1306
+ SURFTRAK_TC 1.000000
1307
+ TCAL_ENABLED 0
1308
+ TEMP1_TYPE 0
1309
+ TEMP2_TYPE 0
1310
+ TEMP3_TYPE 0
1311
+ TEMP_LOG 0
1312
+ TERRAIN_CACHE_SZ 12
1313
+ TERRAIN_ENABLE 1
1314
+ TERRAIN_MARGIN 0.050000
1315
+ TERRAIN_OFS_MAX 30.000000
1316
+ TERRAIN_OPTIONS 0
1317
+ TERRAIN_SPACING 100
1318
+ THROW_ALT_ACSND 3.000000
1319
+ THROW_ALT_DCSND 1.000000
1320
+ THROW_ALT_MAX 0
1321
+ THROW_ALT_MIN 0
1322
+ THROW_MOT_START 0
1323
+ THROW_NEXTMODE 18
1324
+ THROW_TYPE 0
1325
+ THR_DZ 100
1326
+ TKOFF_RPM_MAX 0
1327
+ TKOFF_RPM_MIN 0
1328
+ TKOFF_SLEW_TIME 2.000000
1329
+ TKOFF_THR_MAX 0.900000
1330
+ TUNE 0
1331
+ TUNE_MAX 0.000000
1332
+ TUNE_MIN 0.000000
1333
+ VISO_TYPE 0
1334
+ VTX_ENABLE 0
1335
+ WINCH_TYPE 0
1336
+ WPNAV_ACCEL 250.000000
1337
+ WPNAV_ACCEL_C 0.000000
1338
+ WPNAV_ACCEL_Z 100.000000
1339
+ WPNAV_JERK 1.000000
1340
+ WPNAV_RADIUS 200.000000
1341
+ WPNAV_RFND_USE 1
1342
+ WPNAV_SPEED 1000.000000
1343
+ WPNAV_SPEED_DN 150.000000
1344
+ WPNAV_SPEED_UP 250.000000
1345
+ WPNAV_TER_MARGIN 10.000000
1346
+ WP_NAVALT_MIN 0.000000
1347
+ WP_YAW_BEHAVIOR 2
1348
+ WVANE_ENABLE 0
1349
+ ZIGZ_AUTO_ENABLE 0
{drone → misc}/drone_chat.py RENAMED
File without changes
{drone → misc}/hf_model.py RENAMED
File without changes
requirements.txt CHANGED
@@ -1,11 +1,15 @@
1
- streamlit
2
  pandas
3
  numpy
4
  matplotlib
5
  seaborn
6
- smolagents
7
  python-dotenv
8
- transformers
9
- huggingface-hub
10
  dronekit
11
  pymavlink
 
 
 
 
 
 
 
 
 
 
1
  pandas
2
  numpy
3
  matplotlib
4
  seaborn
 
5
  python-dotenv
 
 
6
  dronekit
7
  pymavlink
8
+ litellm
9
+ ollama
10
+ rich
11
+ click
12
+ pydantic
13
+ pydantic-settings
14
+ typer
15
+ prompt-toolkit
setup.py CHANGED
@@ -1,16 +1,38 @@
1
  from setuptools import setup, find_packages
2
 
 
 
 
 
 
 
3
  setup(
4
  name="deepdrone",
5
- version="0.1.0",
6
- description="DeepDrone - AI-powered drone control and mission planning",
 
 
7
  author="DeepDrone Team",
8
  packages=find_packages(),
9
- install_requires=[
10
- "dronekit",
11
- "smolagents",
12
- "streamlit",
13
- "huggingface_hub",
14
- "python-dotenv",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  ],
16
  )
 
1
  from setuptools import setup, find_packages
2
 
3
+ with open("README.md", "r", encoding="utf-8") as fh:
4
+ long_description = fh.read()
5
+
6
+ with open("requirements.txt", "r", encoding="utf-8") as fh:
7
+ requirements = [line.strip() for line in fh.readlines() if line.strip() and not line.startswith("#")]
8
+
9
  setup(
10
  name="deepdrone",
11
+ version="1.0.0",
12
+ description="DeepDrone - AI-powered drone control terminal application",
13
+ long_description=long_description,
14
+ long_description_content_type="text/markdown",
15
  author="DeepDrone Team",
16
  packages=find_packages(),
17
+ include_package_data=True,
18
+ install_requires=requirements,
19
+ entry_points={
20
+ "console_scripts": [
21
+ "deepdrone=main:main",
22
+ ],
23
+ },
24
+ python_requires=">=3.8",
25
+ classifiers=[
26
+ "Development Status :: 4 - Beta",
27
+ "Intended Audience :: Developers",
28
+ "License :: OSI Approved :: MIT License",
29
+ "Operating System :: OS Independent",
30
+ "Programming Language :: Python :: 3",
31
+ "Programming Language :: Python :: 3.8",
32
+ "Programming Language :: Python :: 3.9",
33
+ "Programming Language :: Python :: 3.10",
34
+ "Programming Language :: Python :: 3.11",
35
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
36
+ "Topic :: System :: Hardware :: Hardware Drivers",
37
  ],
38
  )
simulate_drone.py ADDED
@@ -0,0 +1,234 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Drone SITL (Software In The Loop) Simulator
4
+ Starts a virtual drone for testing DeepDrone commands.
5
+ """
6
+
7
+ import subprocess
8
+ import sys
9
+ import time
10
+ import socket
11
+ import threading
12
+ from pathlib import Path
13
+
14
+ def check_mavproxy_installed():
15
+ """Check if MAVProxy is installed."""
16
+ try:
17
+ result = subprocess.run(['mavproxy.py', '--help'],
18
+ capture_output=True, text=True, timeout=5)
19
+ return result.returncode == 0
20
+ except (subprocess.TimeoutExpired, FileNotFoundError):
21
+ return False
22
+
23
+ def check_ardupilot_installed():
24
+ """Check if ArduPilot SITL is available."""
25
+ try:
26
+ result = subprocess.run(['sim_vehicle.py', '--help'],
27
+ capture_output=True, text=True, timeout=5)
28
+ return result.returncode == 0
29
+ except (subprocess.TimeoutExpired, FileNotFoundError):
30
+ return False
31
+
32
+ def find_available_port(start_port=14550):
33
+ """Find an available UDP port starting from start_port."""
34
+ for port in range(start_port, start_port + 100):
35
+ try:
36
+ with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
37
+ s.bind(('127.0.0.1', port))
38
+ return port
39
+ except OSError:
40
+ continue
41
+ return None
42
+
43
+ def start_simple_sitl(port=14550):
44
+ """Start a simple SITL simulation using ArduPilot."""
45
+ print(f"🚁 Starting ArduPilot SITL on port {port}...")
46
+
47
+ try:
48
+ # Try to start ArduPilot SITL
49
+ cmd = [
50
+ 'sim_vehicle.py',
51
+ '-v', 'ArduCopter',
52
+ '--out', f'udp:127.0.0.1:{port}',
53
+ '--map',
54
+ '--console'
55
+ ]
56
+
57
+ process = subprocess.Popen(
58
+ cmd,
59
+ stdout=subprocess.PIPE,
60
+ stderr=subprocess.PIPE,
61
+ text=True
62
+ )
63
+
64
+ return process, port
65
+
66
+ except FileNotFoundError:
67
+ print("❌ ArduPilot SITL not found. Please install ArduPilot.")
68
+ return None, None
69
+
70
+ def start_mavproxy_sitl(port=14550):
71
+ """Start SITL using MAVProxy."""
72
+ print(f"🚁 Starting MAVProxy SITL on port {port}...")
73
+
74
+ try:
75
+ cmd = [
76
+ 'mavproxy.py',
77
+ '--master', 'tcp:127.0.0.1:5760',
78
+ '--out', f'udp:127.0.0.1:{port}',
79
+ '--aircraft', 'test'
80
+ ]
81
+
82
+ process = subprocess.Popen(
83
+ cmd,
84
+ stdout=subprocess.PIPE,
85
+ stderr=subprocess.PIPE,
86
+ text=True
87
+ )
88
+
89
+ return process, port
90
+
91
+ except FileNotFoundError:
92
+ print("❌ MAVProxy not found.")
93
+ return None, None
94
+
95
+ def create_basic_simulator(port=14550):
96
+ """Create a very basic drone simulator for testing."""
97
+ print(f"🚁 Starting basic drone simulator on port {port}...")
98
+ print("⚠️ This is a minimal simulator for testing purposes only.")
99
+
100
+ # Create a simple UDP server that responds to basic MAVLink messages
101
+ import socket
102
+ import struct
103
+
104
+ def simulator_thread():
105
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
106
+ sock.bind(('127.0.0.1', port))
107
+ sock.settimeout(1.0)
108
+
109
+ print(f"✅ Basic simulator listening on 127.0.0.1:{port}")
110
+
111
+ while True:
112
+ try:
113
+ data, addr = sock.recvfrom(1024)
114
+ # Echo back a simple response
115
+ sock.sendto(data, addr)
116
+ except socket.timeout:
117
+ continue
118
+ except KeyboardInterrupt:
119
+ break
120
+
121
+ sock.close()
122
+
123
+ thread = threading.Thread(target=simulator_thread, daemon=True)
124
+ thread.start()
125
+
126
+ return thread, port
127
+
128
+ def print_connection_info(port):
129
+ """Print connection information."""
130
+ connection_string = f"udp:127.0.0.1:{port}"
131
+
132
+ print("\n" + "="*60)
133
+ print("🚁 DRONE SIMULATOR STARTED")
134
+ print("="*60)
135
+ print(f"📡 Connection String: {connection_string}")
136
+ print(f"🌐 IP Address: 127.0.0.1")
137
+ print(f"🔌 Port: {port}")
138
+ print("="*60)
139
+ print("\n💡 To connect DeepDrone:")
140
+ print(f" 1. Run: python main.py")
141
+ print(f" 2. Choose your AI provider")
142
+ print(f" 3. In chat, say: 'Connect to {connection_string}'")
143
+ print("\n🎯 Example commands once connected:")
144
+ print(" • 'Take off to 30 meters'")
145
+ print(" • 'Fly in a square pattern'")
146
+ print(" • 'Show battery status'")
147
+ print(" • 'Return home and land'")
148
+ print("\n⚠️ Press Ctrl+C to stop the simulator")
149
+ print("="*60)
150
+
151
+ def main():
152
+ """Main function to start the drone simulator."""
153
+ print("🚁 DeepDrone Simulator Starting...")
154
+ print("Checking for available drone simulation software...\n")
155
+
156
+ # Find available port
157
+ port = find_available_port()
158
+ if not port:
159
+ print("❌ No available ports found. Please check your network configuration.")
160
+ return
161
+
162
+ simulator_process = None
163
+ simulator_thread = None
164
+
165
+ try:
166
+ # Try ArduPilot SITL first
167
+ if check_ardupilot_installed():
168
+ print("✅ ArduPilot SITL found. Starting professional simulation...")
169
+ simulator_process, port = start_simple_sitl(port)
170
+
171
+ if simulator_process:
172
+ print_connection_info(port)
173
+ simulator_process.wait()
174
+
175
+ elif check_mavproxy_installed():
176
+ print("✅ MAVProxy found. Starting MAVProxy simulation...")
177
+ simulator_process, port = start_mavproxy_sitl(port)
178
+
179
+ if simulator_process:
180
+ print_connection_info(port)
181
+ simulator_process.wait()
182
+
183
+ else:
184
+ print("⚠️ No professional drone simulation software found.")
185
+ print("Installing ArduPilot SITL is recommended for full simulation.")
186
+ print("Falling back to basic simulator for testing...")
187
+
188
+ simulator_thread, port = create_basic_simulator(port)
189
+ print_connection_info(port)
190
+
191
+ # Keep the basic simulator running
192
+ try:
193
+ while True:
194
+ time.sleep(1)
195
+ except KeyboardInterrupt:
196
+ pass
197
+
198
+ except KeyboardInterrupt:
199
+ print("\n🛑 Stopping drone simulator...")
200
+
201
+ finally:
202
+ if simulator_process:
203
+ simulator_process.terminate()
204
+ try:
205
+ simulator_process.wait(timeout=5)
206
+ except subprocess.TimeoutExpired:
207
+ simulator_process.kill()
208
+
209
+ print("✅ Drone simulator stopped.")
210
+
211
+ def install_instructions():
212
+ """Print installation instructions for drone simulation software."""
213
+ print("\n📋 To install professional drone simulation:")
214
+ print("\n🔧 ArduPilot SITL (Recommended):")
215
+ print(" git clone https://github.com/ArduPilot/ardupilot.git")
216
+ print(" cd ardupilot")
217
+ print(" git submodule update --init --recursive")
218
+ print(" ./Tools/environment_install/install-prereqs-ubuntu.sh -y")
219
+ print(" . ~/.profile")
220
+ print(" ./waf configure --board sitl")
221
+ print(" ./waf copter")
222
+ print(" echo 'export PATH=$PATH:$HOME/ardupilot/Tools/autotest' >> ~/.bashrc")
223
+ print(" source ~/.bashrc")
224
+
225
+ print("\n🔧 MAVProxy (Alternative):")
226
+ print(" pip install MAVProxy")
227
+
228
+ print("\n💡 For now, you can use the basic simulator for testing.")
229
+
230
+ if __name__ == "__main__":
231
+ if len(sys.argv) > 1 and sys.argv[1] == "--install-help":
232
+ install_instructions()
233
+ else:
234
+ main()
terrain/S36E149.DAT ADDED
File without changes
test_ollama_features.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test script to demonstrate the improved Ollama features.
4
+ """
5
+
6
+ from rich.console import Console
7
+ from rich.panel import Panel
8
+
9
+ console = Console()
10
+
11
+ def demo_ollama_features():
12
+ """Demo the new Ollama features."""
13
+
14
+ console.print(Panel(
15
+ "[bold green]🚀 Enhanced Ollama Integration Demo[/bold green]\n\n"
16
+ "[dim]This shows the improved Ollama handling in DeepDrone[/dim]",
17
+ border_style="bright_green",
18
+ padding=(1, 2)
19
+ ))
20
+
21
+ console.print("\n[bold cyan]✨ New Ollama Features:[/bold cyan]\n")
22
+
23
+ features = [
24
+ "🔍 **Auto-Detection**: Automatically finds your local Ollama models",
25
+ "📥 **Smart Installation**: Offers to install missing models automatically",
26
+ "🎯 **Popular Suggestions**: Shows recommended models if none are installed",
27
+ "⚡ **No API Key**: Skips API key entry for local models",
28
+ "🔧 **Connection Help**: Clear instructions if Ollama isn't running",
29
+ "📊 **Status Command**: Use '/ollama' in chat to check model status"
30
+ ]
31
+
32
+ for feature in features:
33
+ console.print(f" {feature}")
34
+
35
+ console.print("\n[bold yellow]🎯 Ollama Workflow:[/bold yellow]\n")
36
+
37
+ workflow = [
38
+ "[bold]1. Select Provider:[/bold] Choose 'Ollama' from the provider list",
39
+ "[bold]2. Model Detection:[/bold] Shows your local models automatically",
40
+ "[bold]3. Install Missing:[/bold] Offers to download models you don't have",
41
+ "[bold]4. No API Key:[/bold] Automatically skips API key entry",
42
+ "[bold]5. Connection Test:[/bold] Verifies Ollama is working",
43
+ "[bold]6. Chat Ready:[/bold] Start controlling drones with local AI!"
44
+ ]
45
+
46
+ for step in workflow:
47
+ console.print(f" {step}")
48
+
49
+ console.print("\n[bold green]💡 Example Experience:[/bold green]\n")
50
+
51
+ example = """[cyan]Provider Selection:[/cyan] 6. Ollama
52
+ [cyan]Model Detection:[/cyan] ✅ Found: llama3.1:latest, codestral:latest
53
+ [cyan]User Choice:[/cyan] "phi3" (not installed locally)
54
+ [cyan]Smart Install:[/cyan] "Would you like to install phi3? [Y/n]"
55
+ [cyan]Download:[/cyan] 📥 Installing phi3... ✅ Success!
56
+ [cyan]API Key:[/cyan] ⏭️ Skipped (local model)
57
+ [cyan]Test:[/cyan] ✅ Connection successful!
58
+ [cyan]Chat Ready:[/cyan] 🚁 DeepDrone ready with local AI!"""
59
+
60
+ console.print(Panel(
61
+ example,
62
+ title="[bold]Ollama Setup Flow[/bold]",
63
+ border_style="blue"
64
+ ))
65
+
66
+ console.print("\n[bold magenta]🔧 Chat Commands:[/bold magenta]\n")
67
+
68
+ commands = [
69
+ "[cyan]/ollama[/cyan] - Show Ollama status and available models",
70
+ "[cyan]/status[/cyan] - General system status including AI model",
71
+ "[cyan]/help[/cyan] - All available commands"
72
+ ]
73
+
74
+ for cmd in commands:
75
+ console.print(f" {cmd}")
76
+
77
+ console.print("\n[bold red]⚠️ Troubleshooting:[/bold red]\n")
78
+
79
+ issues = [
80
+ "[bold]No models found:[/bold] Run 'ollama pull llama3.1'",
81
+ "[bold]Connection refused:[/bold] Run 'ollama serve' in terminal",
82
+ "[bold]Model not found:[/bold] DeepDrone will offer to install it",
83
+ "[bold]Ollama not installed:[/bold] Download from https://ollama.com"
84
+ ]
85
+
86
+ for issue in issues:
87
+ console.print(f" • {issue}")
88
+
89
+ console.print(f"\n[bold green]🎉 Ready to use local AI for drone control![/bold green]")
90
+
91
+ if __name__ == "__main__":
92
+ demo_ollama_features()
tests/__init__.py DELETED
@@ -1,8 +0,0 @@
1
- """
2
- Test modules for the DeepDrone project.
3
-
4
- This package contains test scripts to verify the functionality of:
5
- - Drone connection
6
- - Mission planning and execution
7
- - Agent interactions
8
- """
 
 
 
 
 
 
 
 
 
tests/test_agent_mission.py DELETED
@@ -1,179 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Test the ability of the DroneAssistant to plan and execute missions
4
- based on natural language requests.
5
-
6
- This script simulates a user asking the agent to create a mission plan and execute it.
7
- """
8
-
9
- import os
10
- import time
11
- import json
12
- import sys
13
- from drone.drone_chat import DroneAssistant, generate_mission_plan
14
- from drone.drone_control import connect_drone, disconnect_drone
15
- from drone.hf_model import HfApiModel, Message
16
- from drone import compatibility_fix # Import for Python 3.10+ compatibility
17
-
18
- # Import the simplified model that works with smolagents
19
- from tests.test_simple_agent import SimplePlaceholderModel, final_answer
20
-
21
- # Test cases - different natural language requests for missions
22
- TEST_CASES = [
23
- "Create a mission plan for a survey mission that takes 20 minutes and execute it on the simulator.",
24
- "I need to inspect a building. Can you make a plan for a 15-minute inspection mission and fly it?",
25
- "Plan a delivery mission to these coordinates and execute it: 37.7749, -122.4194. It should take about 10 minutes.",
26
- "Plan and execute a simple square pattern flight around my current position.",
27
- ]
28
-
29
- def setup_drone_agent():
30
- """Create and initialize a DroneAssistant for testing."""
31
- print("Setting up drone agent...")
32
-
33
- # Check if HF_TOKEN is set in environment variables
34
- hf_token = os.environ.get("HF_TOKEN", "")
35
- if not hf_token:
36
- print("WARNING: No Hugging Face API token found. Using a placeholder model.")
37
- # Use our simplified placeholder model instead of the previous complex one
38
- model = SimplePlaceholderModel()
39
- else:
40
- # Use the real model if API token is available
41
- model = HfApiModel(
42
- max_tokens=2096,
43
- temperature=0.7,
44
- model_id='Qwen/Qwen2.5-Coder-32B-Instruct'
45
- )
46
-
47
- # Create the drone assistant with the required tools
48
- drone_agent = DroneAssistant(
49
- tools=[generate_mission_plan],
50
- model=model
51
- )
52
-
53
- return drone_agent
54
-
55
- def execute_mission_from_plan(mission_plan):
56
- """Execute a mission based on the provided plan using DroneKit."""
57
- print("\nExecuting mission from plan...")
58
-
59
- # Parse the mission plan
60
- try:
61
- if isinstance(mission_plan, str):
62
- plan = eval(mission_plan) # Convert string representation to dict
63
- else:
64
- plan = mission_plan
65
-
66
- print(f"Mission type: {plan.get('mission_type')}")
67
- print(f"Duration: {plan.get('duration_minutes')} minutes")
68
- print(f"Flight pattern: {plan.get('flight_pattern')}")
69
- print(f"Recommended altitude: {plan.get('recommended_altitude')}")
70
-
71
- # Connect to the simulator
72
- print("\nConnecting to simulator...")
73
- connected = connect_drone('udp:127.0.0.1:14550')
74
-
75
- if not connected:
76
- print("Failed to connect to the simulator. Make sure it's running.")
77
- return False
78
-
79
- print("Connected to simulator!")
80
- print("Simulating mission execution...")
81
-
82
- # Here we would normally execute the actual mission
83
- # For testing purposes, we'll just simulate the execution
84
- for i in range(5):
85
- print(f"Mission progress: {i*20}%")
86
- time.sleep(1)
87
-
88
- print("Mission completed successfully!")
89
- disconnect_drone()
90
- return True
91
-
92
- except Exception as e:
93
- print(f"Error executing mission: {str(e)}")
94
- return False
95
-
96
- def run_test_case(drone_agent, test_case):
97
- """Run a single test case with the drone agent."""
98
- print(f"\n----- TESTING CASE: '{test_case}' -----")
99
-
100
- # Simulate a user asking the agent
101
- print(f"\nUSER: {test_case}")
102
-
103
- # Get the agent's response
104
- response = drone_agent.chat(test_case)
105
- print(f"\nAGENT: {response}")
106
-
107
- # Check if the response contains or implies a mission plan
108
- mission_keywords = ["mission plan", "flight plan", "waypoints", "coordinates"]
109
- has_mission_plan = any(keyword in response.lower() for keyword in mission_keywords)
110
-
111
- if not has_mission_plan:
112
- print("FAIL: Agent did not create a mission plan.")
113
- return False
114
-
115
- # Extract the mission plan and execute it
116
- # For a real implementation, we would need to parse the response more carefully
117
- # Here we'll just call the generate_mission_plan function directly
118
-
119
- if "survey" in test_case.lower():
120
- mission_type = "survey"
121
- elif "inspect" in test_case.lower():
122
- mission_type = "inspection"
123
- elif "delivery" in test_case.lower():
124
- mission_type = "delivery"
125
- else:
126
- mission_type = "custom"
127
-
128
- if "minute" in test_case.lower():
129
- # Try to extract the duration
130
- import re
131
- duration_match = re.search(r'(\d+)\s*minute', test_case)
132
- duration = int(duration_match.group(1)) if duration_match else 15
133
- else:
134
- duration = 15
135
-
136
- print(f"\nGenerating mission plan for {mission_type} mission with duration {duration} minutes...")
137
- mission_plan = generate_mission_plan(mission_type=mission_type, duration_minutes=duration)
138
- print(f"\nGenerated plan: {mission_plan}")
139
-
140
- # Execute the mission plan
141
- result = execute_mission_from_plan(mission_plan)
142
-
143
- if result:
144
- print("PASS: Successfully executed the mission plan.")
145
- return True
146
- else:
147
- print("FAIL: Could not execute the mission plan.")
148
- return False
149
-
150
- def run_all_tests():
151
- """Run all test cases and report results."""
152
- drone_agent = setup_drone_agent()
153
-
154
- results = []
155
- for test_case in TEST_CASES:
156
- result = run_test_case(drone_agent, test_case)
157
- results.append(result)
158
-
159
- # Print summary
160
- print("\n----- TEST SUMMARY -----")
161
- for i, (test, result) in enumerate(zip(TEST_CASES, results)):
162
- status = "PASS" if result else "FAIL"
163
- print(f"Test {i+1}: {status} - '{test[:40]}...'")
164
-
165
- success_rate = sum(results) / len(results) * 100
166
- print(f"\nOverall Success Rate: {success_rate:.1f}%")
167
-
168
- return all(results)
169
-
170
- if __name__ == "__main__":
171
- print("Testing DroneAssistant's ability to plan and execute missions...")
172
- success = run_all_tests()
173
-
174
- if success:
175
- print("\nAll tests passed! The agent can successfully plan and execute missions.")
176
- exit(0)
177
- else:
178
- print("\nSome tests failed. The agent needs improvement.")
179
- exit(1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/test_connection.py DELETED
@@ -1,33 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Basic connection test for DroneKit to ArduPilot SITL
4
- """
5
-
6
- import time
7
- import sys
8
- from dronekit import connect, APIException
9
-
10
- # Connect to the Vehicle using a different port to avoid conflicts
11
- print("Connecting to vehicle on udp:127.0.0.1:14550...")
12
- try:
13
- vehicle = connect('udp:127.0.0.1:14550', wait_ready=True, timeout=60)
14
- except APIException as e:
15
- print(f"Connection failed: {e}")
16
- sys.exit(1)
17
- except Exception as e:
18
- print(f"Error: {e}")
19
- sys.exit(1)
20
-
21
- # Get some vehicle attributes (state)
22
- print("Connection successful!")
23
- print("Get some vehicle attribute values:")
24
- print(f" GPS: {vehicle.gps_0}")
25
- print(f" Battery: {vehicle.battery}")
26
- print(f" Last Heartbeat: {vehicle.last_heartbeat}")
27
- print(f" Is Armable?: {vehicle.is_armable}")
28
- print(f" System status: {vehicle.system_status.state}")
29
- print(f" Mode: {vehicle.mode.name}")
30
-
31
- # Close vehicle object
32
- vehicle.close()
33
- print("Test complete.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/test_mission.py DELETED
@@ -1,136 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- DroneKit-Python Mission Test Script
4
-
5
- This script demonstrates how to connect to the ArduPilot SITL simulator,
6
- create a simple mission (square pattern), and execute it.
7
- """
8
-
9
- import time
10
- import math
11
- import sys
12
- import argparse
13
- from drone import compatibility_fix # Import the compatibility fix for Python 3.10+
14
- from drone.drone_control import DroneController
15
- from dronekit import connect, VehicleMode, LocationGlobalRelative
16
-
17
- def get_args():
18
- """Parse command line arguments."""
19
- parser = argparse.ArgumentParser(description='Test mission script for DeepDrone')
20
- parser.add_argument('--connect',
21
- help="Vehicle connection target string. If not specified, SITL automatically started.",
22
- default='udp:127.0.0.1:14550')
23
- return parser.parse_args()
24
-
25
- def main():
26
- # Parse connection string
27
- args = get_args()
28
- connection_string = args.connect
29
-
30
- print(f"Connecting to vehicle on: {connection_string}")
31
-
32
- try:
33
- # Connect to the Vehicle
34
- print("Connecting to vehicle on %s" % connection_string)
35
- vehicle = connect(connection_string, wait_ready=True, timeout=60)
36
-
37
- # Get some vehicle attributes (state)
38
- print("Get some vehicle attribute values:")
39
- print(" GPS: %s" % vehicle.gps_0)
40
- print(" Battery: %s" % vehicle.battery)
41
- print(" Last Heartbeat: %s" % vehicle.last_heartbeat)
42
- print(" Is Armable?: %s" % vehicle.is_armable)
43
- print(" System status: %s" % vehicle.system_status.state)
44
- print(" Mode: %s" % vehicle.mode.name)
45
-
46
- # Define the home position (current position where script is run)
47
- home_position = vehicle.location.global_relative_frame
48
- print("Home position: %s" % home_position)
49
-
50
- # Define a square mission
51
- offset = 0.0001 # Approximately 11 meters at the equator
52
-
53
- # Create a mission with a square pattern
54
- print("Creating mission waypoints...")
55
- waypoints = [
56
- # North
57
- LocationGlobalRelative(home_position.lat + offset, home_position.lon, 20),
58
- # Northeast
59
- LocationGlobalRelative(home_position.lat + offset, home_position.lon + offset, 20),
60
- # East
61
- LocationGlobalRelative(home_position.lat, home_position.lon + offset, 20),
62
- # Return to Launch
63
- LocationGlobalRelative(home_position.lat, home_position.lon, 20),
64
- ]
65
-
66
- # Arm the vehicle
67
- print("Arming motors")
68
- vehicle.mode = VehicleMode("GUIDED")
69
- vehicle.armed = True
70
-
71
- # Wait until armed
72
- while not vehicle.armed:
73
- print("Waiting for arming...")
74
- time.sleep(1)
75
-
76
- print("Taking off to 20 meters")
77
- vehicle.simple_takeoff(20) # Take off to 20m
78
-
79
- # Wait until the vehicle reaches a safe height
80
- while True:
81
- print("Altitude: %s" % vehicle.location.global_relative_frame.alt)
82
- # Break and return when we reach target altitude or close to it
83
- if vehicle.location.global_relative_frame.alt >= 19:
84
- print("Reached target altitude")
85
- break
86
- time.sleep(1)
87
-
88
- # Fly through the waypoints
89
- for i, waypoint in enumerate(waypoints):
90
- print(f"Flying to waypoint {i+1}")
91
- vehicle.simple_goto(waypoint)
92
-
93
- # Start timer for waypoint timeout
94
- start_time = time.time()
95
-
96
- # Wait until we reach the waypoint
97
- while True:
98
- # Calculate distance to waypoint
99
- current = vehicle.location.global_relative_frame
100
- distance_to_waypoint = math.sqrt(
101
- (waypoint.lat - current.lat)**2 +
102
- (waypoint.lon - current.lon)**2) * 1.113195e5
103
-
104
- print(f"Distance to waypoint: {distance_to_waypoint:.2f} meters")
105
-
106
- # Break if we're within 3 meters of the waypoint
107
- if distance_to_waypoint < 3:
108
- print(f"Reached waypoint {i+1}")
109
- break
110
-
111
- # Break if we've been flying to this waypoint for more than 60 seconds
112
- if time.time() - start_time > 60:
113
- print(f"Timed out reaching waypoint {i+1}, continuing to next waypoint")
114
- break
115
-
116
- time.sleep(2)
117
-
118
- # Return to home
119
- print("Returning to home")
120
- vehicle.mode = VehicleMode("RTL")
121
-
122
- # Wait for the vehicle to land
123
- while vehicle.armed:
124
- print("Waiting for landing and disarm...")
125
- time.sleep(2)
126
-
127
- print("Mission complete!")
128
-
129
- # Close vehicle object
130
- vehicle.close()
131
-
132
- except Exception as e:
133
- print(f"Error: {str(e)}")
134
-
135
- if __name__ == "__main__":
136
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/test_mission_planning.py DELETED
@@ -1,131 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Simplified test script for mission planning and execution.
4
- This script tests the mission planning and execution functionality directly,
5
- without using the DroneAssistant or smolagents.
6
- """
7
-
8
- import time
9
- import math
10
- import sys
11
- import json
12
- from drone.drone_chat import generate_mission_plan
13
- from drone.drone_control import connect_drone, disconnect_drone, takeoff, land, return_home
14
- from drone import compatibility_fix # Import for Python 3.10+ compatibility
15
-
16
- def test_mission_planning():
17
- """Test the mission planning functionality."""
18
- print("\n----- TESTING MISSION PLANNING -----")
19
-
20
- # Test different mission types
21
- mission_types = ["survey", "inspection", "delivery", "custom"]
22
- durations = [10, 15, 20, 5]
23
-
24
- for mission_type, duration in zip(mission_types, durations):
25
- print(f"\nGenerating {mission_type} mission plan for {duration} minutes...")
26
-
27
- mission_plan = generate_mission_plan(mission_type=mission_type, duration_minutes=duration)
28
-
29
- # Parse the mission plan
30
- if isinstance(mission_plan, str):
31
- try:
32
- plan = eval(mission_plan) # Convert string representation to dict
33
- print("Successfully parsed mission plan:")
34
- print(f" Mission type: {plan.get('mission_type')}")
35
- print(f" Duration: {plan.get('duration_minutes')} minutes")
36
- print(f" Flight pattern: {plan.get('flight_pattern')}")
37
- print(f" Recommended altitude: {plan.get('recommended_altitude')} meters")
38
- print(f" Waypoint count: {len(plan.get('waypoints', []))}")
39
- print(" Mission description:", plan.get('description', '')[:50] + "...")
40
- except Exception as e:
41
- print(f"Error parsing mission plan: {str(e)}")
42
- print("Raw mission plan:", mission_plan)
43
- else:
44
- print("Mission plan is not a string:", type(mission_plan))
45
- print(mission_plan)
46
-
47
- print("\nMission planning test completed.")
48
- return True
49
-
50
- def test_mission_execution(mission_type="survey", duration=10):
51
- """Test the mission execution functionality using the simulator."""
52
- print("\n----- TESTING MISSION EXECUTION -----")
53
-
54
- # Generate a mission plan
55
- print(f"Generating {mission_type} mission plan for {duration} minutes...")
56
- mission_plan = generate_mission_plan(mission_type=mission_type, duration_minutes=duration)
57
-
58
- # Parse the mission plan
59
- try:
60
- if isinstance(mission_plan, str):
61
- plan = eval(mission_plan) # Convert string representation to dict
62
- else:
63
- plan = mission_plan
64
-
65
- print("Mission plan details:")
66
- print(f" Mission type: {plan.get('mission_type')}")
67
- print(f" Duration: {plan.get('duration_minutes')} minutes")
68
- print(f" Flight pattern: {plan.get('flight_pattern')}")
69
- print(f" Recommended altitude: {plan.get('recommended_altitude')} meters")
70
- print(f" Waypoint count: {len(plan.get('waypoints', []))}")
71
-
72
- # Connect to the simulator
73
- print("\nConnecting to simulator...")
74
- success = connect_drone('udp:127.0.0.1:14550')
75
-
76
- if not success:
77
- print("Failed to connect to the simulator. Make sure it's running.")
78
- return False
79
-
80
- print("Connected to simulator!")
81
-
82
- # Execute the mission
83
- # For the test, we'll just print the waypoints instead of actually flying
84
- print("\nSimulating mission execution...")
85
- print(f"Taking off to {plan.get('recommended_altitude')} meters...")
86
- time.sleep(2)
87
-
88
- print("Flying mission waypoints:")
89
- waypoints = plan.get('waypoints', [])
90
- for i, waypoint in enumerate(waypoints):
91
- print(f" Waypoint {i+1}: {waypoint}")
92
- time.sleep(1)
93
-
94
- print("Returning to home...")
95
- time.sleep(2)
96
-
97
- print("Landing...")
98
- time.sleep(2)
99
-
100
- print("Mission completed successfully!")
101
- disconnect_drone()
102
- return True
103
-
104
- except Exception as e:
105
- print(f"Error executing mission: {str(e)}")
106
- return False
107
-
108
- def main():
109
- """Run all tests."""
110
- print("Testing mission planning and execution...")
111
-
112
- # Test mission planning
113
- planning_success = test_mission_planning()
114
-
115
- # Test mission execution
116
- execution_success = test_mission_execution("survey", 10)
117
-
118
- # Print test summary
119
- print("\n----- TEST SUMMARY -----")
120
- print(f"Mission Planning Test: {'PASS' if planning_success else 'FAIL'}")
121
- print(f"Mission Execution Test: {'PASS' if execution_success else 'FAIL'}")
122
-
123
- if planning_success and execution_success:
124
- print("\nAll tests passed! The mission planning and execution are working properly.")
125
- return 0
126
- else:
127
- print("\nSome tests failed. Check the output above for details.")
128
- return 1
129
-
130
- if __name__ == "__main__":
131
- sys.exit(main())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/test_prompt_examples.md DELETED
@@ -1,120 +0,0 @@
1
- # DeepDrone Test Prompts
2
-
3
- This document contains example prompts that can be used to test the DeepDrone agent's ability to understand natural language mission requests, plan missions, and execute them.
4
-
5
- ## Running the Tests
6
-
7
- 1. Start the ArduPilot SITL simulator:
8
- ```bash
9
- cd ~/ardupilot && ./Tools/autotest/sim_vehicle.py -v ArduCopter --console --map
10
- ```
11
-
12
- 2. In a new terminal, run the DeepDrone application:
13
- ```bash
14
- cd ~/deepdrone && streamlit run main.py
15
- ```
16
-
17
- 3. Use one of the example prompts below in the chat interface to test the agent's capabilities.
18
-
19
- ## Example Prompts for Testing
20
-
21
- ### Basic Mission Planning
22
-
23
- #### Example 1: Square Pattern Mission
24
- ```
25
- Plan and execute a simple square pattern flight around my current position with sides of 50 meters at an altitude of 20 meters.
26
- ```
27
-
28
- Expected behavior:
29
- - Agent should generate a square-shaped mission plan
30
- - Mission should include 4 waypoints forming a square
31
- - Altitude should be set to 20 meters
32
- - Agent will connect to the simulator and execute the mission
33
-
34
- #### Example 2: Survey Mission
35
- ```
36
- I need to create a survey mission for a 100x100 meter area. It should take about 15 minutes and cover the area systematically with a camera.
37
- ```
38
-
39
- Expected behavior:
40
- - Agent should generate a survey mission plan with grid pattern
41
- - Mission plan should specify recommended altitude for survey (40-60 meters)
42
- - Plan should include information about camera settings and overlap
43
- - Agent will offer to execute the mission on the simulator
44
-
45
- #### Example 3: Inspection Mission
46
- ```
47
- Create an inspection mission for a tower structure. The mission should orbit around a central point at varying distances and capture detailed images.
48
- ```
49
-
50
- Expected behavior:
51
- - Agent should generate an inspection mission plan with orbital pattern
52
- - Mission should recommend lower altitude (5-20 meters)
53
- - Plan should include waypoints at different heights and distances
54
- - Agent will offer to execute the mission on the simulator
55
-
56
- ### Specific Execution Instructions
57
-
58
- #### Example 4: Delivery Mission with Specific Coordinates
59
- ```
60
- Plan a delivery mission to these coordinates: 37.7749, -122.4194. Make sure to maintain at least 30 meters altitude en route and avoid populated areas.
61
- ```
62
-
63
- Expected behavior:
64
- - Agent should generate a delivery mission plan with the specified coordinates
65
- - Mission should set 30+ meters as the flight altitude
66
- - Plan should mention safety considerations
67
- - Agent will offer to execute the mission on the simulator
68
-
69
- #### Example 5: Custom Mission with Multiple Waypoints
70
- ```
71
- I need a custom mission with the following waypoints:
72
- 1. Take off to 15 meters
73
- 2. Fly to 50 meters north of home position
74
- 3. Then 50 meters east
75
- 4. Then 50 meters south
76
- 5. Return to home and land
77
- ```
78
-
79
- Expected behavior:
80
- - Agent should generate a custom mission plan with the specified waypoints
81
- - Plan should include exact coordinates for each waypoint
82
- - Agent will offer to execute the mission on the simulator
83
-
84
- ## Troubleshooting
85
-
86
- If the agent doesn't respond correctly to any of these prompts, check the following:
87
-
88
- 1. Make sure the SITL simulator is running properly
89
- 2. Verify that you have set the HF_TOKEN environment variable for the Hugging Face API
90
- 3. Check that the DroneKit connection to the simulator is working
91
- 4. Look for any error messages in the terminal
92
-
93
- ## Expected Response Format
94
-
95
- A typical response from the agent should include:
96
-
97
- 1. Acknowledgment of the mission request
98
- 2. A detailed mission plan including:
99
- - Mission type
100
- - Duration
101
- - Flight pattern
102
- - Altitude recommendations
103
- - Waypoint information
104
- 3. Options to execute the mission or modify the plan
105
-
106
- Example:
107
- ```
108
- I'll create a survey mission plan for your 100x100 meter area.
109
-
110
- Mission Plan:
111
- - Type: Survey
112
- - Duration: 15 minutes
113
- - Flight pattern: Grid with 70% overlap
114
- - Recommended altitude: 50 meters
115
- - Camera settings: 4K resolution, 1 shot every 2 seconds
116
-
117
- The plan includes 12 waypoints in a grid pattern to ensure complete coverage of the area.
118
-
119
- Would you like me to execute this mission on the simulator?
120
- ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/test_simple_agent.py DELETED
@@ -1,75 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Simplified test for the DroneAssistant with proper smolagents format support
4
- """
5
-
6
- import os
7
- import sys
8
- from drone.drone_chat import DroneAssistant, generate_mission_plan
9
- from drone.hf_model import Message
10
-
11
- def final_answer(answer):
12
- """Final answer function for smolagents"""
13
- print(f"FINAL ANSWER: {answer}")
14
- return answer
15
-
16
- class SimplePlaceholderModel:
17
- """A very simple placeholder model that always returns a properly formatted response"""
18
-
19
- def __call__(self, messages):
20
- """Called when used as a function"""
21
- return self.generate(messages)
22
-
23
- def generate(self, messages, **kwargs):
24
- """Generate a response with proper smolagents formatting"""
25
- mission_type = "survey"
26
- duration = 15
27
-
28
- # Format the response in the way smolagents expects with proper code formatting
29
- response = f"""Thought: I will create a {mission_type} mission plan for {duration} minutes and execute it on the simulator.
30
- Code:
31
- ```py
32
- mission_plan = generate_mission_plan(mission_type="{mission_type}", duration_minutes={duration})
33
- print(f"Generated mission plan: {{mission_plan}}")
34
- final_answer(f"I've created a {mission_type} mission plan that will take approximately {duration} minutes to execute. The plan includes waypoints for a square pattern around your current position.")
35
- ```<end_code>"""
36
-
37
- return Message(response)
38
-
39
- def test_simple_agent():
40
- """Test the drone assistant with a simple model"""
41
- print("\n=== Testing Simple Agent ===")
42
-
43
- # Create placeholder model
44
- model = SimplePlaceholderModel()
45
-
46
- # Create drone assistant
47
- assistant = DroneAssistant(
48
- tools=[generate_mission_plan],
49
- model=model
50
- )
51
-
52
- # Test a simple mission planning request
53
- user_message = "Plan a simple square pattern mission around my current position."
54
-
55
- print(f"\nUser: {user_message}")
56
-
57
- try:
58
- response = assistant.chat(user_message)
59
- print(f"\nAgent response: {response}")
60
- return True
61
- except Exception as e:
62
- print(f"\nError: {str(e)}")
63
- print(f"Error type: {type(e)}")
64
- import traceback
65
- traceback.print_exc()
66
- return False
67
-
68
- if __name__ == "__main__":
69
- success = test_simple_agent()
70
- if success:
71
- print("\nTest passed!")
72
- sys.exit(0)
73
- else:
74
- print("\nTest failed!")
75
- sys.exit(1)