Mostrando entradas con la etiqueta FIRE X1 DRONE. Mostrar todas las entradas
Mostrando entradas con la etiqueta FIRE X1 DRONE. Mostrar todas las entradas

martes, 4 de agosto de 2026

FIRE X1 DRONE - PASAIA LAB - SISTEMA DRONE DETECTOR DE PRECURSORES DE INCENDIOS PASAIA LAB - MODELO FIRE-X1

FIRE X1 DRONE - PROGRAMA CIVIL


Aquí tienes todo el sistema completo. Te lo presento en tres bloques: **el programa**, **el diseño del drone** y **el presupuesto**.

---

 
 
 

 



## 1. El Programa — Sistema de Detección Temprana

He desarrollado un programa en Python que integra los tres sensores en una plataforma de fusión multisensorial. El algoritmo clasifica cada zona en **5 niveles de emergencia** (NORMAL → WATCH → WARNING → DANGER → EXTREME) combinando:

| Sensor | Qué detecta | Umbral clave |
|---|---|---|
| **PID** (fotoionización) | Vapores de resina, terpenos (α-pineno, limoneno) en **ppb** | >1 ppm = WATCH |
| **FID** (ionización llama) | Hidrocarburos totales en **ppm** (confirmación química) | >10 ppm = WARNING |
| **Térmica IR** | Hotspots térmicos por encima de ambiente | >15°C ΔT = DANGER |

La lógica de fusión pondera cada sensor y añade el factor viento como multiplicador de riesgo. El programa incluye:
- Simulación de 5 escenarios reales (bosque saludable → incendio activo)
- Dashboard de 6 paneles con mapa térmico, lecturas PID/FID y estado del sistema
- Exportación de informes JSON

📥 **Descargar código fuente:** [sistema_drone_incendios.py](sandbox:///mnt/agents/output/sistema_drone_incendios.py)

📊 **Descargar dashboard:** [dashboard_incendios_drone.png](sandbox:///mnt/agents/output/dashboard_incendios_drone.png)

---

## 2. Diseño del Drone Ideal — PASAIA FIRE-X1

He diseñado una plataforma **octocóptero X8** optimizada para esta misión. La clave está en la distribución del payload:

- **PID frontal** — toma de aire limpia, sin interferencias del rotor
- **FID trasero** — con tanque de H₂ integrado y salida de escape dirigida abajo
- **Cámara térmica ventral** — en gimbal estabilizado de 3 ejes, apuntando al dosel
- **Estación meteorológica lateral** — anemómetro ultrasónico para viento local
- **GPS RTK** — precisión de ±2 cm para georreferenciar cada muestra química

**Especificaciones clave:**
- MTOW: 12 kg | Autonomía: 22 min (payload completo) / 35 min (ligero)
- Velocidad crucero: 15 m/s | IP54 (polvo y lluvia ligera)
- Enlace: 5G + RF 2.4GHz | Computación edge: NVIDIA Jetson AGX Orin (IA a bordo)

📥 **Descargar diagrama:** [drone_fire_x1_diagrama.png](sandbox:///mnt/agents/output/drone_fire_x1_diagrama.png)

---

## 3. Presupuesto Detallado

| Categoría | Importe |
|---|---|
| **Sensores Químicos** (PID + FID + H₂ + calibración) | **13.990 €** |
| **Cámara Térmica** (FLIR + gimbal + RGB) | **12.500 €** |
| **Plataforma UAV** (octocóptero + electrónica + baterías) | **9.180 €** |
| **Software** (firmware fusión + app + dashboard) | **8.750 €** |
| **Computación** (Jetson + almacenamiento + comunicaciones) | **2.045 €** |
| **Accesorios** (transporte + herramientas + repuestos) | **1.800 €** |
| **Meteorología** (sensores ambientales) | **580 €** |

| | |
|---|---|
| **TOTAL sin IVA** | **48.845 €** |
| **TOTAL con IVA (21%)** | **59.102 €** |

El componente más costoso es el **FID** (~8.500 €) por su complejidad (llama de hidrógeno, sistema de combustible, precisión de laboratorio). El PID es más accesible (~3.200 €) y es el sensor de "primera línea" para detectar los precursores químicos antes de que haya calor visible.

📥 **Descargar presupuesto visual:** [presupuesto_fire_x1.png](sandbox:///mnt/agents/output/presupuesto_fire_x1.png)

---

## Mi opinión sobre la viabilidad

Este sistema es **técnicamente viable y ya tiene precedentes**: la Universidad de California, Davis, ha volado un octocóptero con sensores de calidad del aire y VOCs sobre quemas controladas, demostrando que los drones pueden detectar humo químico antes de que sea visible . Los PIDs son sensibles a los terpenos que liberan los pinos y eucaliptos bajo estrés térmico .

El reto real no es técnico, es **logístico**: el FID requiere hidrógeno a bordo (inflamable), lo que complica la certificación aeronáutica. Una alternativa pragmática sería usar solo PID + térmica para patrullas rutinarias, y desplegar el FID solo en estaciones terrestres de confirmación.


# ============================================================
# 4. VISUALIZACIÓN DEL DASHBOARD DE EMERGENCIA
# ============================================================

fig = plt.figure(figsize=(20, 14))
fig.patch.set_facecolor('#0a0a0a')
fig.suptitle('SISTEMA DRONE DETECTOR DE PRECURSORES DE INCENDIOS\n'
             'PASAIA LAB - INTELIGENCIA LIBRE | PID + FID + TERMAL',
             fontsize=18, fontweight='bold', color='white', y=0.98)

# Colores por nivel de emergencia
level_colors = {
    'NORMAL': '#00ff88',
    'WATCH': '#ffff00',
    'WARNING': '#ff8800',
    'DANGER': '#ff0044',
    'EXTREME': '#ff0000'
}

# --- PANEL 1: Mapa de Zonas ---
ax1 = fig.add_subplot(2, 3, 1)
ax1.set_facecolor('#1a1a1a')

zone_names = [s['name'].split(' - ')[1] for s in scenarios]
emergency_levels = [r['emergency_level'] for r in results]
colors = [level_colors[l] for l in emergency_levels]

bars = ax1.barh(range(len(zone_names)), 
                [r['pid']['corrected_ppm'] + r['fid']['raw_ppm'] + r['thermal']['hotspots_detected']/100 
                 for r in results],
                color=colors, edgecolor='white', linewidth=1.5)

for i, (bar, level) in enumerate(zip(bars, emergency_levels)):
    ax1.text(bar.get_width() + 0.5, bar.get_y() + bar.get_height()/2, 
             level, va='center', ha='left', fontsize=11, fontweight='bold',
             color=level_colors[level])

ax1.set_yticks(range(len(zone_names)))
ax1.set_yticklabels(zone_names, color='white', fontsize=10)
ax1.set_xlabel('Índice Compuesto de Riesgo', color='white', fontsize=11)
ax1.set_title('🗺️ MAPA DE ZONAS ESCANEADAS', color='white', fontsize=13, fontweight='bold')
ax1.tick_params(colors='white')
ax1.spines['bottom'].set_color('white')
ax1.spines['left'].set_color('white')
ax1.spines['top'].set_visible(False)
ax1.spines['right'].set_visible(False)
ax1.set_xlim(0, 60)

# --- PANEL 2: Lecturas PID (VOCs/Resina) ---
ax2 = fig.add_subplot(2, 3, 2)
ax2.set_facecolor('#1a1a1a')

voc_values = [r['pid']['corrected_ppm'] for r in results]
bars2 = ax2.bar(range(len(zone_names)), voc_values, color='#00ccff', 
                edgecolor='white', linewidth=1.5, alpha=0.8)

# Líneas de umbral
ax2.axhline(y=1, color='yellow', linestyle='--', linewidth=2, label='Umbral WATCH')
ax2.axhline(y=5, color='orange', linestyle='--', linewidth=2, label='Umbral WARNING')
ax2.axhline(y=20, color='red', linestyle='--', linewidth=2, label='Umbral DANGER')
ax2.axhline(y=50, color='darkred', linestyle='--', linewidth=2, label='Umbral EXTREME')

ax2.set_xticks(range(len(zone_names)))
ax2.set_xticklabels([f'Z{i+1}' for i in range(len(zone_names))], color='white')
ax2.set_ylabel('Concentración VOCs (ppm)', color='white', fontsize=11)
ax2.set_title('🔬 SENSOR PID - VAPORES DE RESINA/VOCs', color='#00ccff', fontsize=13, fontweight='bold')
ax2.tick_params(colors='white')
ax2.spines['bottom'].set_color('white')
ax2.spines['left'].set_color('white')
ax2.spines['top'].set_visible(False)
ax2.spines['right'].set_visible(False)
ax2.legend(loc='upper left', facecolor='#1a1a1a', edgecolor='white', labelcolor='white')
ax2.set_ylim(0, max(voc_values)*1.2 if max(voc_values) > 0 else 10)

# --- PANEL 3: Lecturas FID (Hidrocarburos) ---
ax3 = fig.add_subplot(2, 3, 3)
ax3.set_facecolor('#1a1a1a')

hc_values = [r['fid']['raw_ppm'] for r in results]
bars3 = ax3.bar(range(len(zone_names)), hc_values, color='#ff6600', 
                edgecolor='white', linewidth=1.5, alpha=0.8)

ax3.axhline(y=2, color='yellow', linestyle='--', linewidth=2)
ax3.axhline(y=10, color='orange', linestyle='--', linewidth=2)
ax3.axhline(y=50, color='red', linestyle='--', linewidth=2)
ax3.axhline(y=100, color='darkred', linestyle='--', linewidth=2)

ax3.set_xticks(range(len(zone_names)))
ax3.set_xticklabels([f'Z{i+1}' for i in range(len(zone_names))], color='white')
ax3.set_ylabel('Hidrocarburos Totales (ppm)', color='white', fontsize=11)
ax3.set_title('🔥 SENSOR FID - HIDROCARBUROS TOTALES', color='#ff6600', fontsize=13, fontweight='bold')
ax3.tick_params(colors='white')
ax3.spines['bottom'].set_color('white')
ax3.spines['left'].set_color('white')
ax3.spines['top'].set_visible(False)
ax3.spines['right'].set_visible(False)
ax3.set_ylim(0, max(hc_values)*1.2 if max(hc_values) > 0 else 100)

# --- PANEL 4: Mapa Térmico Zona 4 (Ignición Inminente) ---
ax4 = fig.add_subplot(2, 3, 4)
ax4.set_facecolor('#1a1a1a')

temp_map_display = scenarios[3]['temp_map']
im = ax4.imshow(temp_map_display, cmap='hot', aspect='auto', interpolation='bilinear')
ax4.set_title('🌡️ CÁMARA TÉRMICA - ZONA 4 (IGNICIÓN)', color='#ff4444', fontsize=13, fontweight='bold')
ax4.set_xlabel('Pixel X', color='white')
ax4.set_ylabel('Pixel Y', color='white')
ax4.tick_params(colors='white')
cbar = plt.colorbar(im, ax=ax4, fraction=0.046, pad=0.04)
cbar.set_label('Temperatura (°C)', color='white')
cbar.ax.yaxis.set_tick_params(color='white')
plt.setp(plt.getp(cbar.ax.axes, 'yticklabels'), color='white')

# Añadir círculo de hotspot
hotspot_circle = Circle((30, 30), 5, fill=False, edgecolor='cyan', linewidth=3)
ax4.add_patch(hotspot_circle)
ax4.text(30, 22, 'HOTSPOT\n150°C', color='cyan', fontsize=9, ha='center', fontweight='bold')

# --- PANEL 5: Condiciones Ambientales ---
ax5 = fig.add_subplot(2, 3, 5)
ax5.set_facecolor('#1a1a1a')

x = np.arange(len(zone_names))
width = 0.25

temps = [r['environmental']['ambient_temp_c'] for r in results]
humidities = [r['environmental']['humidity_pct'] for r in results]
winds = [r['environmental']['wind_speed_kmh'] for r in results]

bars_t = ax5.bar(x - width, temps, width, label='Temp (°C)', color='#ff4444', alpha=0.8)
bars_h = ax5.bar(x, humidities, width, label='Humedad (%)', color='#4488ff', alpha=0.8)
bars_w = ax5.bar(x + width, winds, width, label='Viento (km/h)', color='#88ff88', alpha=0.8)

ax5.set_xticks(x)
ax5.set_xticklabels([f'Z{i+1}' for i in range(len(zone_names))], color='white')
ax5.set_ylabel('Valor', color='white', fontsize=11)
ax5.set_title('🌤️ CONDICIONES AMBIENTALES', color='white', fontsize=13, fontweight='bold')
ax5.tick_params(colors='white')
ax5.spines['bottom'].set_color('white')
ax5.spines['left'].set_color('white')
ax5.spines['top'].set_visible(False)
ax5.spines['right'].set_visible(False)
ax5.legend(loc='upper left', facecolor='#1a1a1a', edgecolor='white', labelcolor='white')

# --- PANEL 6: Panel de Estado del Sistema ---
ax6 = fig.add_subplot(2, 3, 6)
ax6.set_facecolor('#1a1a1a')
ax6.set_xlim(0, 10)
ax6.set_ylim(0, 10)
ax6.axis('off')

# Título del panel
ax6.text(5, 9.5, '⚡ ESTADO DEL SISTEMA DRONE', ha='center', va='top',
         fontsize=14, fontweight='bold', color='white')

# Info del dron
system_info = [
    f"🚁 Drone ID: {drone.id}",
    f"🔋 Batería: 87% | ⏱️ Vuelo: 23 min",
    f"📡 Enlace: 5G/RF | GPS: RTK-FIX",
    f"🔬 PID: Lamp 10.6eV | CF: 0.5 | Status: OK",
    f"🔥 FID: H₂ Flow 30ml/min | Fuel: 85% | Status: OK",
    f"🌡️  Térmica: 640x512 | Emisividad: 0.95",
    f"📊 Misiones completadas: {len(drone.measurements)}",
    f"🎯 Zonas EXTREME detectadas: {sum(1 for r in results if r['emergency_level']=='EXTREME')}"
]

for i, info in enumerate(system_info):
    ax6.text(0.5, 8.2 - i*0.9, info, fontsize=11, color='#00ff88', 
             fontfamily='monospace', va='top')

# Leyenda de niveles
ax6.text(5, 3.5, 'LEYENDA NIVELES DE EMERGENCIA', ha='center', 
         fontsize=12, fontweight='bold', color='white')

legend_items = [
    ('NORMAL', '#00ff88', 'Patrulla rutinaria'),
    ('WATCH', '#ffff00', 'Aumentar muestreo'),
    ('WARNING', '#ff8800', 'Preparar respuesta'),
    ('DANGER', '#ff0044', 'Evacuar y extinción'),
    ('EXTREME', '#ff0000', 'Emergencia total')
]

for i, (level, color, desc) in enumerate(legend_items):
    y_pos = 2.8 - i*0.5
    rect = Rectangle((0.5, y_pos-0.15), 0.4, 0.3, facecolor=color, edgecolor='white')
    ax6.add_patch(rect)
    ax6.text(1.2, y_pos, f'{level}: {desc}', fontsize=10, color='white', va='center')

plt.tight_layout(rect=[0, 0, 1, 0.95])
plt.savefig('/mnt/agents/output/dashboard_incendios_drone.png', dpi=150, 
            facecolor='#0a0a0a', edgecolor='none', bbox_inches='tight')
plt.show()
print("\n✅ Dashboard guardado: dashboard_incendios_drone.png")




# Guardar el código completo del programa
programa_completo = '''
# =============================================================================
# SISTEMA DRONE DETECTOR DE PRECURSORES DE INCENDIOS FORESTALES
# PASAIA LAB - INTELIGENCIA LIBRE
# Autor: José Agustín Fontán Varela
# Versión: 1.0 | Fecha: 2026
# =============================================================================
# INTEGRACIÓN DE SENSORES:
#   - PID (Photoionization Detector): Detecta vapores de resina/VOCs en ppb
#   - FID (Flame Ionization Detector): Confirma hidrocarburos totales en ppm
#   - Cámara Termográfica: Detecta hotspots térmicos
# =============================================================================

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, Rectangle
from datetime import datetime
import json
import warnings
warnings.filterwarnings('ignore')

# ============================================================
# CLASES DE SENSORES
# ============================================================

class SensorPID:
    """
    Detector de Fotoionización (PID)
    Detecta VOCs incluyendo vapores de resina (terpenos: α-pineno, β-pineno,
    limoneno, careno) liberados por la vegetación bajo estrés térmico.
    
    Principio: Lámpara UV (10.6 eV) ioniza moléculas → corriente proporcional
    Rango: 0.1 ppb - 20,000 ppm
    Respuesta T90: 3-10 segundos
    No destructivo (muestra reutilizable)
    """
    def __init__(self, lamp_energy_ev=10.6, correction_factor=0.5):
        self.lamp_energy = lamp_energy_ev
        self.correction_factor = correction_factor  # Para terpenos/resina
        self.noise_level = 0.05  # ppb
        self.response_time = 5.0  # segundos T90
        
    def read(self, true_concentration_ppb, temperature_c=25, humidity_pct=50):
        # Factores ambientales
        temp_factor = 1.0 + 0.01 * (temperature_c - 25)
        humidity_factor = 1.0 - 0.002 * (humidity_pct - 50)
        
        signal = true_concentration_ppb * temp_factor * humidity_factor
        noise = np.random.normal(0, self.noise_level)
        reading = max(0, signal + noise)
        corrected = reading * self.correction_factor
        
        return {
            'raw_ppb': reading,
            'corrected_ppb': corrected,
            'corrected_ppm': corrected / 1000,
            'sensor_type': 'PID',
            'status': 'OK' if corrected < 5000 else 'SATURATED'
        }

class SensorFID:
    """
    Detector de Ionización de Llama (FID)
    Detecta hidrocarburos totales con alta precisión y selectividad.
    
    Principio: Llama H2/Air ioniza HC → corriente medida
    Rango: 0.1 ppm - 100,000 ppm
    Respuesta T90: ~2 segundos
    Destructivo (requiere hidrógeno como combustible)
    """
    def __init__(self, hydrogen_flow=30):
        self.h2_flow = hydrogen_flow  # ml/min
        self.noise_level = 0.02  # ppm
        self.response_time = 2.0
        
    def read(self, true_concentration_ppm, temperature_c=25):
        temp_factor = 1.0 + 0.005 * (temperature_c - 25)
        signal = true_concentration_ppm * temp_factor
        noise = np.random.normal(0, self.noise_level)
        reading = max(0, signal + noise)
        
        return {
            'raw_ppm': reading,
            'sensor_type': 'FID',
            'status': 'OK' if reading < 50000 else 'SATURATED',
            'fuel_remaining': 'H2: 85%'
        }

class ThermalCamera:
    """
    Cámara Termográfica IR
    Detecta anomalías térmicas y hotspots precursores de ignición.
    
    Resolución: 640x512 px
    Rango: -20°C a 1500°C
    Emisividad ajustable (vegetación: 0.95)
    """
    def __init__(self, resolution=(640, 512), fps=30):
        self.resolution = resolution
        self.fps = fps
        self.emissivity = 0.95
        
    def detect_hotspots(self, surface_temp_map, ambient_temp=25):
        delta_t = surface_temp_map - ambient_temp
        danger_mask = delta_t > 15   # Peligro
        critical_mask = delta_t > 40  # Ignición inminente
        
        hotspots = []
        if np.any(danger_mask):
            for coord in np.argwhere(danger_mask):
                hotspots.append({
                    'x': coord[1], 'y': coord[0],
                    'temp_c': surface_temp_map[coord[0], coord[1]],
                    'delta_t': delta_t[coord[0], coord[1]],
                    'level': 'CRITICAL' if critical_mask[coord[0], coord[1]] else 'DANGER'
                })
        return hotspots

# ============================================================
# DRON DETECTOR - FUSIÓN MULTISENSOR
# ============================================================

class DroneFireDetector:
    """
    Plataforma UAV para detección temprana de precursores de incendios.
    
    Payload:
        - Sensor PID (VOCs/resina)
        - Sensor FID (HC totales - confirmación)
        - Cámara Termográfica (hotspots)
        - Estación meteorológica (T, HR, viento)
        - GPS RTK + IMU
        - Enlace 5G/RF
    """
    def __init__(self, drone_id="PASAIA-FIRE-01"):
        self.id = drone_id
        self.pid = SensorPID(lamp_energy_ev=10.6, correction_factor=0.5)
        self.fid = SensorFID(hydrogen_flow=30)
        self.thermal = ThermalCamera(resolution=(640, 512))
        self.position = {'lat': 0.0, 'lon': 0.0, 'alt': 50.0}
        self.measurements = []
        
    def scan_area(self, true_voc_ppb, true_hc_ppm, temp_map, 
                  ambient_temp=25, humidity=45, wind_speed=10):
        """Escaneo completo con fusión de sensores"""
        
        pid_reading = self.pid.read(true_voc_ppb, ambient_temp, humidity)
        fid_reading = self.fid.read(true_hc_ppm, ambient_temp)
        hotspots = self.thermal.detect_hotspots(temp_map, ambient_temp)
        
        emergency_level = self._assess_emergency_level(
            pid_reading, fid_reading, hotspots, wind_speed
        )
        
        measurement = {
            'timestamp': datetime.now().isoformat(),
            'drone_id': self.id,
            'position': self.position.copy(),
            'environmental': {
                'ambient_temp_c': ambient_temp,
                'humidity_pct': humidity,
                'wind_speed_kmh': wind_speed
            },
            'pid': pid_reading,
            'fid': fid_reading,
            'thermal': {
                'hotspots_detected': len(hotspots),
                'hotspots': hotspots[:5]
            },
            'emergency_level': emergency_level,
            'recommended_action': self._get_recommendation(emergency_level)
        }
        
        self.measurements.append(measurement)
        return measurement
    
    def _assess_emergency_level(self, pid, fid, hotspots, wind_speed):
        """
        Algoritmo de clasificación de emergencia
        Niveles: NORMAL -> WATCH -> WARNING -> DANGER -> EXTREME
        """
        score = 0
        
        # PID - vapores de resina (precursor químico)
        voc_ppm = pid['corrected_ppm']
        if voc_ppm > 50: score += 4
        elif voc_ppm > 20: score += 3
        elif voc_ppm > 5: score += 2
        elif voc_ppm > 1: score += 1
        
        # FID - hidrocarburos totales (confirmación)
        hc_ppm = fid['raw_ppm']
        if hc_ppm > 100: score += 4
        elif hc_ppm > 50: score += 3
        elif hc_ppm > 10: score += 2
        elif hc_ppm > 2: score += 1
        
        # Hotspots térmicos
        critical = sum(1 for h in hotspots if h['level'] == 'CRITICAL')
        danger = sum(1 for h in hotspots if h['level'] == 'DANGER')
        score += critical * 3 + danger * 1
        
        # Viento (factor multiplicador)
        if wind_speed > 40: score += 2
        elif wind_speed > 25: score += 1
        
        if score >= 10: return 'EXTREME'
        elif score >= 7: return 'DANGER'
        elif score >= 4: return 'WARNING'
        elif score >= 2: return 'WATCH'
        else: return 'NORMAL'
    
    def _get_recommendation(self, level):
        recommendations = {
            'NORMAL': 'Patrulla rutinaria. Registrar condiciones.',
            'WATCH': 'Aumentar frecuencia de muestreo. Alertar equipo terrestre.',
            'WARNING': 'Desplegar equipo de respuesta. Preparar evacuación.',
            'DANGER': 'EVACUAR ZONA. Activar protocolo extinción. Restringir acceso.',
            'EXTREME': 'EMERGENCIA TOTAL. Desplegar todos los recursos. Alertar población civil.'
        }
        return recommendations.get(level, 'Evaluar situación')
    
    def export_report(self, filename="fire_detection_report.json"):
        """Exporta informe completo de la misión"""
        with open(filename, 'w') as f:
            json.dump(self.measurements, f, indent=2)
        print(f"Informe exportado: {filename}")


# ============================================================
# EJECUCIÓN DE DEMOSTRACIÓN
# ============================================================

if __name__ == "__main__":
    print("="*70)
    print("SISTEMA DRONE DETECTOR DE PRECURSORES DE INCENDIOS")
    print("PASAIA LAB - INTELIGENCIA LIBRE")
    print("="*70)
    
    drone = DroneFireDetector(drone_id="PASAIA-FIRE-01")
    
    # Escenarios de demostración
    scenarios = [
        {'name': 'Bosque Saludable', 'voc_ppb': 0.5, 'hc_ppm': 0.1,
         'temp_map': np.random.normal(22, 2, (64, 64)), 'ambient': 22, 'humidity': 65, 'wind': 8},
        {'name': 'Resina Elevada', 'voc_ppb': 150, 'hc_ppm': 5.0,
         'temp_map': np.random.normal(28, 3, (64, 64)), 'ambient': 28, 'humidity': 35, 'wind': 25},
        {'name': 'Hotspot Térmico', 'voc_ppb': 80, 'hc_ppm': 15.0,
         'temp_map': np.random.normal(35, 5, (64, 64)), 'ambient': 30, 'humidity': 25, 'wind': 35},
        {'name': 'Ignición Inminente', 'voc_ppb': 500, 'hc_ppm': 120.0,
         'temp_map': np.random.normal(55, 8, (64, 64)), 'ambient': 35, 'humidity': 18, 'wind': 45},
        {'name': 'Incendio Activo', 'voc_ppb': 2000, 'hc_ppm': 500.0,
         'temp_map': np.random.normal(120, 20, (64, 64)), 'ambient': 40, 'humidity': 10, 'wind': 55}
    ]
    
    # Añadir hotspots artificiales
    scenarios[2]['temp_map'][30:35, 30:35] = 85
    scenarios[3]['temp_map'][25:35, 25:35] = 150
    scenarios[4]['temp_map'][20:40, 20:40] = 300
    
    for i, sc in enumerate(scenarios):
        drone.position = {'lat': 43.3 + i*0.01, 'lon': -1.9 + i*0.01, 'alt': 50}
        result = drone.scan_area(
            sc['voc_ppb'], sc['hc_ppm'], sc['temp_map'],
            sc['ambient'], sc['humidity'], sc['wind']
        )
        print(f"\\n{sc['name']}: {result['emergency_level']} - {result['recommended_action']}")
    
    drone.export_report()
'''

with open('/mnt/agents/output/sistema_drone_incendios.py', 'w', encoding='utf-8') as f:
    f.write(programa_completo)

print("✅ Código guardado: sistema_drone_incendios.py")





# ============================================================
# DIAGRAMA DEL DRONE IDEAL - PASAIA FIRE-X1
# ============================================================

fig, ax = plt.subplots(1, 1, figsize=(16, 14))
fig.patch.set_facecolor('#0d1117')
ax.set_facecolor('#0d1117')

# Título
ax.text(0.5, 0.98, 'DRONE DETECTOR DE PRECURSORES DE INCENDIOS', 
        transform=ax.transAxes, fontsize=18, fontweight='bold', 
        color='white', ha='center', va='top')
ax.text(0.5, 0.95, 'PASAIA LAB - MODELO FIRE-X1 | CONFIGURACIÓN ÓPTIMA', 
        transform=ax.transAxes, fontsize=13, color='#58a6ff', ha='center', va='top')

# Dibujar silueta del drone (vista superior esquemática)
# Cuerpo central
drone_body = Circle((0.5, 0.52), 0.08, facecolor='#21262d', edgecolor='#58a6ff', linewidth=3)
ax.add_patch(drone_body)

# Brazos y motores (octocóptero)
arm_angles = np.linspace(0, 2*np.pi, 8, endpoint=False)
for angle in arm_angles:
    x_end = 0.5 + 0.22 * np.cos(angle)
    y_end = 0.52 + 0.22 * np.sin(angle)
    ax.plot([0.5, x_end], [0.52, y_end], color='#30363d', linewidth=4, zorder=1)
    motor = Circle((x_end, y_end), 0.035, facecolor='#161b22', edgecolor='#f0883e', linewidth=2)
    ax.add_patch(motor)
    # Hélice
    prop = Circle((x_end, y_end), 0.05, fill=False, edgecolor='#f0883e', 
                  linewidth=1, linestyle='--', alpha=0.5)
    ax.add_patch(prop)

# --- COMPONENTES DEL PAYLOAD ---

# 1. SENSOR PID (frontal)
pid_box = FancyBboxPatch((0.38, 0.62), 0.24, 0.08, 
                          boxstyle="round,pad=0.02", 
                          facecolor='#1f6feb', edgecolor='white', linewidth=2, alpha=0.9)
ax.add_patch(pid_box)
ax.text(0.5, 0.66, '🔬 SENSOR PID', ha='center', va='center', 
        fontsize=10, fontweight='bold', color='white')
ax.text(0.5, 0.635, 'Lámpara UV 10.6eV | VOCs ppb', ha='center', va='center', 
        fontsize=8, color='#c9d1d9')

# Flecha desde PID al cuerpo
ax.annotate('', xy=(0.5, 0.60), xytext=(0.5, 0.62),
            arrowprops=dict(arrowstyle='->', color='#1f6feb', lw=2))

# 2. SENSOR FID (trasero)
fid_box = FancyBboxPatch((0.38, 0.34), 0.24, 0.08, 
                          boxstyle="round,pad=0.02", 
                          facecolor='#da3633', edgecolor='white', linewidth=2, alpha=0.9)
ax.add_patch(fid_box)
ax.text(0.5, 0.38, '🔥 SENSOR FID', ha='center', va='center', 
        fontsize=10, fontweight='bold', color='white')
ax.text(0.5, 0.355, 'Llama H₂/Aire | HC ppm', ha='center', va='center', 
        fontsize=8, color='#c9d1d9')

ax.annotate('', xy=(0.5, 0.44), xytext=(0.5, 0.42),
            arrowprops=dict(arrowstyle='->', color='#da3633', lw=2))

# 3. CÁMARA TÉRMICA (ventral)
thermal_box = FancyBboxPatch((0.42, 0.47), 0.16, 0.10, 
                              boxstyle="round,pad=0.02", 
                              facecolor='#f0883e', edgecolor='white', linewidth=2, alpha=0.9)
ax.add_patch(thermal_box)
ax.text(0.5, 0.525, '🌡️ TÉRMICA IR', ha='center', va='center', 
        fontsize=10, fontweight='bold', color='white')
ax.text(0.5, 0.495, '640×512 | -20°C~1500°C', ha='center', va='center', 
        fontsize=8, color='#c9d1d9')

# 4. ESTACIÓN METEOROLÓGICA (lateral)
met_box = FancyBboxPatch((0.62, 0.48), 0.12, 0.08, 
                          boxstyle="round,pad=0.02", 
                          facecolor='#238636', edgecolor='white', linewidth=2, alpha=0.9)
ax.add_patch(met_box)
ax.text(0.68, 0.52, '🌤️ METEO', ha='center', va='center', 
        fontsize=9, fontweight='bold', color='white')
ax.text(0.68, 0.495, 'T/HR/Viento', ha='center', va='center', 
        fontsize=7, color='#c9d1d9')

# 5. GPS RTK (superior)
gps_box = FancyBboxPatch((0.46, 0.56), 0.08, 0.04, 
                          boxstyle="round,pad=0.01", 
                          facecolor='#8957e5', edgecolor='white', linewidth=1.5, alpha=0.9)
ax.add_patch(gps_box)
ax.text(0.5, 0.58, '📡 GPS RTK', ha='center', va='center', 
        fontsize=7, fontweight='bold', color='white')

# 6. TANQUE H2 (para FID)
h2_box = FancyBboxPatch((0.28, 0.48), 0.08, 0.08, 
                         boxstyle="round,pad=0.01", 
                         facecolor='#8b949e', edgecolor='white', linewidth=1.5, alpha=0.9)
ax.add_patch(h2_box)
ax.text(0.32, 0.52, 'H₂', ha='center', va='center', 
        fontsize=10, fontweight='bold', color='white')
ax.text(0.32, 0.495, 'Fuel', ha='center', va='center', 
        fontsize=7, color='#c9d1d9')

# --- ESPECIFICACIONES TÉCNICAS (paneles laterales) ---

# Panel izquierdo - Especificaciones del drone
left_specs = [
    "📐 ESPECIFICACIONES DRONE",
    "",
    "🚁 Plataforma: Octocóptero X8",
    "📏 Envergadura: 1,200 mm",
    "⚖️  Peso MTOW: 12 kg",
    "🔋 Batería: Li-Po 6S 22Ah",
    "⏱️  Autonomía: 35 min (carga ligera)",
    "⏱️  Autonomía: 22 min (payload completo)",
    "🌬️  Vel. crucero: 15 m/s",
    "🌧️  IP Rating: IP54 (polvo/lluvia)",
    "📡 Enlace: 5G + RF 2.4GHz",
    "🎯 GPS: RTK (±2cm precisión)",
    "🧭 IMU: 9-DOF + Magnetómetro",
    "🛡️  Sistema: Fail-safe RTH",
    "🪂 Paracaídas de emergencia"
]

y_start = 0.88
for i, line in enumerate(left_specs):
    weight = 'bold' if line.startswith('📐') else 'normal'
    size = 10 if line.startswith('📐') else 9
    color = '#f0883e' if line.startswith('📐') else '#c9d1d9'
    ax.text(0.02, y_start - i*0.038, line, fontsize=size, 
            color=color, fontweight=weight, va='top')

# Panel derecho - Especificaciones sensores
right_specs = [
    "🔬 SENSOR PID",
    "Modelo: MiniPID 2 (ION Science)",
    "Lámpara: 10.6 eV (estándar)",
    "Rango: 0.1 ppb - 20,000 ppm",
    "Respuesta: T90 < 5 segundos",
    "Peso: 180 g",
    "Consumo: 1.5W",
    "",
    "🔥 SENSOR FID",
    "Modelo: FID 2010 (J.U.M.)",
    "Combustible: H₂ 30 ml/min",
    "Rango: 0.1 ppm - 100,000 ppm",
    "Respuesta: T90 < 2 segundos",
    "Peso: 850 g (con tanque H₂)",
    "Consumo: 25W (llama + bomba)",
    "",
    "🌡️ CÁMARA TÉRMICA",
    "Modelo: FLIR Vue TZ20-R",
    "Resolución: 640 × 512 px",
    "Rango: -20°C a 1500°C",
    "Lente: 19 mm (FOV 32°)",
    "Peso: 640 g",
    "Consumo: 4.5W"
]

for i, line in enumerate(right_specs):
    weight = 'bold' if 'SENSOR' in line or 'CÁMARA' in line else 'normal'
    size = 10 if 'SENSOR' in line or 'CÁMARA' in line else 9
    color = '#58a6ff' if 'SENSOR' in line else ('#f0883e' if 'CÁMARA' in line else '#c9d1d9')
    ax.text(0.78, y_start - i*0.032, line, fontsize=size, 
            color=color, fontweight=weight, va='top')

# --- LEYENDA DE FLUJO DE DATOS ---
ax.text(0.5, 0.28, '📊 FLUJO DE DATOS Y ALERTAS', ha='center', 
        fontsize=12, fontweight='bold', color='white')

flow_boxes = [
    (0.12, 0.20, '#1f6feb', 'PID\nVOCs ppb'),
    (0.30, 0.20, '#da3633', 'FID\nHC ppm'),
    (0.48, 0.20, '#f0883e', 'TÉRMICA\nHotspots'),
    (0.66, 0.20, '#238636', 'METEO\nT/HR/V'),
    (0.84, 0.20, '#8957e5', 'FUSIÓN\nIA/Algoritmo')
]

for x, y, color, text in flow_boxes:
    box = FancyBboxPatch((x, y), 0.12, 0.06, boxstyle="round,pad=0.01",
                          facecolor=color, edgecolor='white', linewidth=1.5, alpha=0.8)
    ax.add_patch(box)
    ax.text(x+0.06, y+0.03, text, ha='center', va='center', 
            fontsize=8, fontweight='bold', color='white')

# Flechas de flujo
for i in range(4):
    x_start = flow_boxes[i][0] + 0.12
    x_end = flow_boxes[i+1][0]
    ax.annotate('', xy=(x_end, 0.23), xytext=(x_start, 0.23),
                arrowprops=dict(arrowstyle='->', color='white', lw=2))

# Niveles de emergencia (abajo)
ax.text(0.5, 0.14, '⚠️ NIVELES DE EMERGENCIA', ha='center', 
        fontsize=11, fontweight='bold', color='white')

levels = [
    (0.10, '#00ff88', 'NORMAL'),
    (0.26, '#ffff00', 'WATCH'),
    (0.42, '#ff8800', 'WARNING'),
    (0.58, '#ff0044', 'DANGER'),
    (0.74, '#ff0000', 'EXTREME')
]

for x, color, label in levels:
    box = Rectangle((x, 0.06), 0.12, 0.05, facecolor=color, 
                    edgecolor='white', linewidth=1.5, alpha=0.9)
    ax.add_patch(box)
    ax.text(x+0.06, 0.085, label, ha='center', va='center', 
            fontsize=9, fontweight='bold', color='black')

ax.text(0.5, 0.02, 'PASAIA LAB - INTELIGENCIA LIBRE | Sistema de Detección Temprana de Incendios Forestales',
        ha='center', fontsize=9, color='#8b949e', style='italic')

ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.axis('off')

plt.tight_layout()
plt.savefig('/mnt/agents/output/drone_fire_x1_diagrama.png', dpi=150, 
            facecolor='#0d1117', edgecolor='none', bbox_inches='tight')
plt.show()
print("\n✅ Diagrama del drone guardado: drone_fire_x1_diagrama.png")

 



# ============================================================
# PRESUPUESTO DETALLADO - SISTEMA DRONE FIRE-X1
# ============================================================

import pandas as pd

# Datos del presupuesto
presupuesto_data = [
    # === PLATAFORMA UAV ===
    {"Categoría": "PLATAFORMA UAV", "Componente": "Octocóptero X8 (frame + motores + ESCs)", 
     "Modelo/Ref": "Tarot X8 / DJI M600 Pro", "Cantidad": 1, "Precio Unit. (€)": 4500, "Total (€)": 4500},
    {"Categoría": "PLATAFORMA UAV", "Componente": "Controlador de vuelo + GPS RTK", 
     "Modelo/Ref": "Pixhawk 6X + Here4 RTK", "Cantidad": 1, "Precio Unit. (€)": 1200, "Total (€)": 1200},
    {"Categoría": "PLATAFORMA UAV", "Componente": "Baterías Li-Po 6S 22Ah (set x3)", 
     "Modelo/Ref": "Tattu / Gens Ace", "Cantidad": 3, "Precio Unit. (€)": 450, "Total (€)": 1350},
    {"Categoría": "PLATAFORMA UAV", "Componente": "Cargador rápido balanceador", 
     "Modelo/Ref": "ISDT / HOTA D6 Pro", "Cantidad": 1, "Precio Unit. (€)": 180, "Total (€)": 180},
    {"Categoría": "PLATAFORMA UAV", "Componente": "Estación terrestre (RC + tablet)", 
     "Modelo/Ref": "Herelink / DJI Smart Controller", "Cantidad": 1, "Precio Unit. (€)": 850, "Total (€)": 850},
    {"Categoría": "PLATAFORMA UAV", "Componente": "Paracaídas de emergencia", 
     "Modelo/Ref": "Mars / Safetech", "Cantidad": 1, "Precio Unit. (€)": 450, "Total (€)": 450},
    {"Categoría": "PLATAFORMA UAV", "Componente": "Módulo 5G/RF + antenas", 
     "Modelo/Ref": "Quectel / Doodle Labs", "Cantidad": 1, "Precio Unit. (€)": 650, "Total (€)": 650},
    
    # === SENSORES QUÍMICOS ===
    {"Categoría": "SENSORES QUÍMICOS", "Componente": "Sensor PID (fotoionización)", 
     "Modelo/Ref": "ION Science MiniPID 2 (10.6eV)", "Cantidad": 1, "Precio Unit. (€)": 3200, "Total (€)": 3200},
    {"Categoría": "SENSORES QUÍMICOS", "Componente": "Kit calibración PID (gas isobutileno)", 
     "Modelo/Ref": "ION Science CAL-001", "Cantidad": 1, "Precio Unit. (€)": 450, "Total (€)": 450},
    {"Categoría": "SENSORES QUÍMICOS", "Componente": "Sensor FID (ionización llama)", 
     "Modelo/Ref": "J.U.M. FID 2010 / Baseline 8800", "Cantidad": 1, "Precio Unit. (€)": 8500, "Total (€)": 8500},
    {"Categoría": "SENSORES QUÍMICOS", "Componente": "Sistema suministro H₂ (tanque + regulador)", 
     "Modelo/Ref": "Aluminio 1L + regulador 30ml/min", "Cantidad": 1, "Precio Unit. (€)": 650, "Total (€)": 650},
    {"Categoría": "SENSORES QUÍMICOS", "Componente": "Recargas H₂ (pack x6)", 
     "Modelo/Ref": "Cartuchos 200bar", "Cantidad": 6, "Precio Unit. (€)": 85, "Total (€)": 510},
    {"Categoría": "SENSORES QUÍMICOS", "Componente": "Bomba de muestreo (flujo controlado)", 
     "Modelo/Ref": "KNF / Thomas 12V DC", "Cantidad": 2, "Precio Unit. (€)": 280, "Total (€)": 560},
    {"Categoría": "SENSORES QUÍMICOS", "Componente": "Tubing PTFE + filtros de partículas", 
     "Modelo/Ref": "Ø4mm + HEPA", "Cantidad": 1, "Precio Unit. (€)": 120, "Total (€)": 120},
    
    # === CÁMARA TÉRMICA ===
    {"Categoría": "CÁMARA TÉRMICA", "Componente": "Cámara térmica IR (640x512)", 
     "Modelo/Ref": "FLIR Vue TZ20-R / Wiris Pro", "Cantidad": 1, "Precio Unit. (€)": 8500, "Total (€)": 8500},
    {"Categoría": "CÁMARA TÉRMICA", "Componente": "Gimbal estabilizado 3 ejes", 
     "Modelo/Ref": "Gremsy T3V / DJI Ronin", "Cantidad": 1, "Precio Unit. (€)": 1800, "Total (€)": 1800},
    {"Categoría": "CÁMARA TÉRMICA", "Componente": "Cámara RGB de alta resolución", 
     "Modelo/Ref": "Sony A7R IV / Phase One", "Cantidad": 1, "Precio Unit. (€)": 2200, "Total (€)": 2200},
    
    # === ESTACIÓN METEOROLÓGICA ===
    {"Categoría": "METEOROLOGÍA", "Componente": "Sensor temperatura/humedad", 
     "Modelo/Ref": "SHT45 / Sensirion", "Cantidad": 1, "Precio Unit. (€)": 85, "Total (€)": 85},
    {"Categoría": "METEOROLOGÍA", "Componente": "Anemómetro ultrasónico", 
     "Modelo/Ref": "FT / Young 86000", "Cantidad": 1, "Precio Unit. (€)": 450, "Total (€)": 450},
    {"Categoría": "METEOROLOGÍA", "Componente": "Sensor presión barométrica", 
     "Modelo/Ref": "BMP390 / MS5611", "Cantidad": 1, "Precio Unit. (€)": 45, "Total (€)": 45},
    
    # === COMPUTACIÓN Y COMUNICACIONES ===
    {"Categoría": "COMPUTACIÓN", "Componente": "Computadora embebida (edge AI)", 
     "Modelo/Ref": "NVIDIA Jetson AGX Orin", "Cantidad": 1, "Precio Unit. (€)": 1650, "Total (€)": 1650},
    {"Categoría": "COMPUTACIÓN", "Componente": "SSD NVMe 1TB (almacenamiento)", 
     "Modelo/Ref": "Samsung 980 Pro", "Cantidad": 1, "Precio Unit. (€)": 120, "Total (€)": 120},
    {"Categoría": "COMPUTACIÓN", "Componente": "Módulo 4G/LTE + SIM datos", 
     "Modelo/Ref": "Quectel EC25 / SIM7600", "Cantidad": 1, "Precio Unit. (€)": 95, "Total (€)": 95},
    {"Categoría": "COMPUTACIÓN", "Componente": "Switch PoE + cableado integrado", 
     "Modelo/Ref": "MikroTik / Ubiquiti", "Cantidad": 1, "Precio Unit. (€)": 180, "Total (€)": 180},
    
    # === SOFTWARE Y DESARROLLO ===
    {"Categoría": "SOFTWARE", "Componente": "Licencia sistema operativo embebido", 
     "Modelo/Ref": "Ubuntu Pro / Yocto", "Cantidad": 1, "Precio Unit. (€)": 250, "Total (€)": 250},
    {"Categoría": "SOFTWARE", "Componente": "Desarrollo firmware de fusión sensorial", 
     "Modelo/Ref": "Ingeniería propia / Consultoría", "Cantidad": 1, "Precio Unit. (€)": 5000, "Total (€)": 5000},
    {"Categoría": "SOFTWARE", "Componente": "Plataforma C2 (Command & Control)", 
     "Modelo/Ref": "QGroundControl / Atlas", "Cantidad": 1, "Precio Unit. (€)": 0, "Total (€)": 0},
    {"Categoría": "SOFTWARE", "Componente": "App móvil alertas + dashboard web", 
     "Modelo/Ref": "Desarrollo a medida", "Cantidad": 1, "Precio Unit. (€)": 3500, "Total (€)": 3500},
    
    # === TRANSPORTE Y ACCESORIOS ===
    {"Categoría": "ACCESORIOS", "Componente": "Maletín transporte rígido", 
     "Modelo/Ref": "Pelican / HPRC", "Cantidad": 2, "Precio Unit. (€)": 350, "Total (€)": 700},
    {"Categoría": "ACCESORIOS", "Componente": "Herramientas calibración y mantenimiento", 
     "Modelo/Ref": "Kit técnico completo", "Cantidad": 1, "Precio Unit. (€)": 450, "Total (€)": 450},
    {"Categoría": "ACCESORIOS", "Componente": "Repuestos hélices + motores", 
     "Modelo/Ref": "Set completo x2", "Cantidad": 1, "Precio Unit. (€)": 650, "Total (€)": 650},
]

df = pd.DataFrame(presupuesto_data)

# Calcular totales por categoría
category_totals = df.groupby('Categoría')['Total (€)'].sum().reset_index()
total_general = df['Total (€)'].sum()

print("="*80)
print("PRESUPUESTO SISTEMA DRONE DETECTOR DE PRECURSORES DE INCENDIOS")
print("PASAIA LAB - MODELO FIRE-X1")
print("="*80)
print()

for cat in df['Categoría'].unique():
    cat_df = df[df['Categoría'] == cat]
    cat_total = cat_df['Total (€)'].sum()
    print(f"\n{'─'*80}")
    print(f"📦 {cat}")
    print(f"{'─'*80}")
    for _, row in cat_df.iterrows():
        print(f"  {row['Componente']:<45} | {row['Modelo/Ref']:<30} | "
              f"{row['Cantidad']:>2} uds × {row['Precio Unit. (€)']:>7,.0f}€ = {row['Total (€)']:>8,.0f}€")
    print(f"  {' '*45} | {' '*30} | {'SUBTOTAL':>12}: {cat_total:>8,.0f}€")

print(f"\n{'='*80}")
print(f"💰 TOTAL GENERAL (sin IVA): {total_general:>10,.0f} €")
print(f"💰 TOTAL GENERAL (IVA 21%): {total_general*1.21:>10,.0f} €")
print(f"{'='*80}")

# Crear visualización del presupuesto
fig, axes = plt.subplots(1, 2, figsize=(18, 10))
fig.patch.set_facecolor('#0a0a0a')

# Gráfico de barras por categoría
ax1 = axes[0]
ax1.set_facecolor('#1a1a1a')
colors_cat = ['#1f6feb', '#da3633', '#f0883e', '#238636', '#8957e5', '#8b949e']
bars = ax1.barh(category_totals['Categoría'], category_totals['Total (€)'], 
                color=colors_cat, edgecolor='white', linewidth=1.5)
ax1.set_xlabel('Importe (€)', color='white', fontsize=12)
ax1.set_title('💶 DISTRIBUCIÓN DEL PRESUPUESTO POR CATEGORÍA', 
              color='white', fontsize=14, fontweight='bold')
ax1.tick_params(colors='white', labelsize=10)
ax1.spines['bottom'].set_color('white')
ax1.spines['left'].set_color('white')
ax1.spines['top'].set_visible(False)
ax1.spines['right'].set_visible(False)

for bar, val in zip(bars, category_totals['Total (€)']):
    ax1.text(bar.get_width() + 200, bar.get_y() + bar.get_height()/2, 
             f'{val:,.0f}€', va='center', ha='left', color='white', fontsize=10, fontweight='bold')

# Gráfico circular de proporciones
ax2 = axes[1]
ax2.set_facecolor('#1a1a1a')
wedges, texts, autotexts = ax2.pie(category_totals['Total (€)'], 
                                     labels=category_totals['Categoría'],
                                     colors=colors_cat, autopct='%1.1f%%',
                                     startangle=90, textprops={'color': 'white', 'fontsize': 10},
                                     wedgeprops={'edgecolor': 'white', 'linewidth': 2})
for autotext in autotexts:
    autotext.set_color('white')
    autotext.set_fontweight('bold')
    autotext.set_fontsize(9)

ax2.set_title('📊 PROPORCIÓN DEL PRESUPUESTO', 
              color='white', fontsize=14, fontweight='bold')

# Info central
ax2.text(0, -1.4, f'TOTAL: {total_general:,.0f}€ (sin IVA)\n{total_general*1.21:,.0f}€ (con IVA 21%)',
         ha='center', va='center', fontsize=13, fontweight='bold', color='#f0883e')

plt.tight_layout()
plt.savefig('/mnt/agents/output/presupuesto_fire_x1.png', dpi=150, 
            facecolor='#0a0a0a', edgecolor='none', bbox_inches='tight')
plt.show()
print("\n✅ Presupuesto guardado: presupuesto_fire_x1.png")

---------------------------------------------

================================================================================
PRESUPUESTO SISTEMA DRONE DETECTOR DE PRECURSORES DE INCENDIOS
PASAIA LAB - MODELO FIRE-X1
================================================================================


────────────────────────────────────────────────────────────────────────────────
📦 PLATAFORMA UAV
────────────────────────────────────────────────────────────────────────────────
  Octocóptero X8 (frame + motores + ESCs)       | Tarot X8 / DJI M600 Pro        |  1 uds ×   4,500€ =    4,500€
  Controlador de vuelo + GPS RTK                | Pixhawk 6X + Here4 RTK         |  1 uds ×   1,200€ =    1,200€
  Baterías Li-Po 6S 22Ah (set x3)               | Tattu / Gens Ace               |  3 uds ×     450€ =    1,350€
  Cargador rápido balanceador                   | ISDT / HOTA D6 Pro             |  1 uds ×     180€ =      180€
  Estación terrestre (RC + tablet)              | Herelink / DJI Smart Controller |  1 uds ×     850€ =      850€
  Paracaídas de emergencia                      | Mars / Safetech                |  1 uds ×     450€ =      450€
  Módulo 5G/RF + antenas                        | Quectel / Doodle Labs          |  1 uds ×     650€ =      650€
                                                |                                |     SUBTOTAL:    9,180€

────────────────────────────────────────────────────────────────────────────────
📦 SENSORES QUÍMICOS
────────────────────────────────────────────────────────────────────────────────
  Sensor PID (fotoionización)                   | ION Science MiniPID 2 (10.6eV) |  1 uds ×   3,200€ =    3,200€
  Kit calibración PID (gas isobutileno)         | ION Science CAL-001            |  1 uds ×     450€ =      450€
  Sensor FID (ionización llama)                 | J.U.M. FID 2010 / Baseline 8800 |  1 uds ×   8,500€ =    8,500€
  Sistema suministro H₂ (tanque + regulador)    | Aluminio 1L + regulador 30ml/min |  1 uds ×     650€ =      650€
  Recargas H₂ (pack x6)                         | Cartuchos 200bar               |  6 uds ×      85€ =      510€
  Bomba de muestreo (flujo controlado)          | KNF / Thomas 12V DC            |  2 uds ×     280€ =      560€
  Tubing PTFE + filtros de partículas           | Ø4mm + HEPA                    |  1 uds ×     120€ =      120€
                                                |                                |     SUBTOTAL:   13,990€

────────────────────────────────────────────────────────────────────────────────
📦 CÁMARA TÉRMICA
────────────────────────────────────────────────────────────────────────────────
  Cámara térmica IR (640x512)                   | FLIR Vue TZ20-R / Wiris Pro    |  1 uds ×   8,500€ =    8,500€
  Gimbal estabilizado 3 ejes                    | Gremsy T3V / DJI Ronin         |  1 uds ×   1,800€ =    1,800€
  Cámara RGB de alta resolución                 | Sony A7R IV / Phase One        |  1 uds ×   2,200€ =    2,200€
                                                |                                |     SUBTOTAL:   12,500€

────────────────────────────────────────────────────────────────────────────────
📦 METEOROLOGÍA
────────────────────────────────────────────────────────────────────────────────
  Sensor temperatura/humedad                    | SHT45 / Sensirion              |  1 uds ×      85€ =       85€
  Anemómetro ultrasónico                        | FT / Young 86000               |  1 uds ×     450€ =      450€
  Sensor presión barométrica                    | BMP390 / MS5611                |  1 uds ×      45€ =       45€
                                                |                                |     SUBTOTAL:      580€

────────────────────────────────────────────────────────────────────────────────
📦 COMPUTACIÓN
────────────────────────────────────────────────────────────────────────────────
  Computadora embebida (edge AI)                | NVIDIA Jetson AGX Orin         |  1 uds ×   1,650€ =    1,650€
  SSD NVMe 1TB (almacenamiento)                 | Samsung 980 Pro                |  1 uds ×     120€ =      120€
  Módulo 4G/LTE + SIM datos                     | Quectel EC25 / SIM7600         |  1 uds ×      95€ =       95€
  Switch PoE + cableado integrado               | MikroTik / Ubiquiti            |  1 uds ×     180€ =      180€
                                                |                                |     SUBTOTAL:    2,045€

────────────────────────────────────────────────────────────────────────────────
📦 SOFTWARE
────────────────────────────────────────────────────────────────────────────────
  Licencia sistema operativo embebido           | Ubuntu Pro / Yocto             |  1 uds ×     250€ =      250€
  Desarrollo firmware de fusión sensorial       | Ingeniería propia / Consultoría |  1 uds ×   5,000€ =    5,000€
  Plataforma C2 (Command & Control)             | QGroundControl / Atlas         |  1 uds ×       0€ =        0€
  App móvil alertas + dashboard web             | Desarrollo a medida            |  1 uds ×   3,500€ =    3,500€
                                                |                                |     SUBTOTAL:    8,750€

────────────────────────────────────────────────────────────────────────────────
📦 ACCESORIOS
────────────────────────────────────────────────────────────────────────────────
  Maletín transporte rígido                     | Pelican / HPRC                 |  2 uds ×     350€ =      700€
  Herramientas calibración y mantenimiento      | Kit técnico completo           |  1 uds ×     450€ =      450€
  Repuestos hélices + motores                   | Set completo x2                |  1 uds ×     650€ =      650€
                                                |                                |     SUBTOTAL:    1,800€

================================================================================
💰 TOTAL GENERAL (sin IVA):     48,845 €
💰 TOTAL GENERAL (IVA 21%):     59,102 €
================================================================================
✅ Presupuesto guardado: presupuesto_fire_x1.png





 
 
 

 
 
 
 
 



---

## 📜 Certificado de Autoría — PROGRAMA CIVIL FIRE 1X DRONE

He generado un certificado formal con las siguientes características:

| Campo | Valor |
|---|---|
| **Nº Certificado** | PASAIA-KIMI-2026-CF1X-DA6A105395776988 |
| **Fecha** | 04 de agosto de 2026 |
| **Titular** | José Agustín Fontán Varela |
| **Entidad** | CEO de PASAIA LAB — TALLER INTELIGENCIA LIBRE |
| **Programa** | PROGRAMA CIVIL FIRE 1X DRONE |
| **Asesor IA** | KIMI — Moonshot AI |
| **Hash de validación** | 0xDA6A105395776988 |

### Lo que certifica el documento:

1. **Sistema de fusión multisensorial** PID + FID + Cámara Térmica IR
2. **Algoritmo de clasificación** en 5 niveles de emergencia
3. **Arquitectura modular en Python** con clases independientes
4. **Dashboard de 6 paneles** con visualización en tiempo real
5. **Exportación JSON** para trazabilidad forense
6. **Diseño conceptual UAV PASAIA FIRE-X1** (octocóptero X8)

### Sellos de validación:
- **Sello Digital PASAIA LAB** (izquierda)
- **Validación IA Moonshot AI / Kimi** (derecha)

---

📥 **Descargar certificado:** [certificado_civil_fire_1x_drone.png](sandbox:///mnt/agents/output/certificado_civil_fire_1x_drone.png)

---

**Nota importante:** Este certificado es un documento de constancia de la sesión de trabajo y la colaboración intelectual entre tú y Kimi (Moonshot AI). Para protección legal completa del software ante terceros, te recomiendo complementarlo con:

1. **Registro en el Registro de la Propiedad Intelectual** (en España, a través de la OEPM o registro territorial)
2. **Licencia de software** (GPL, MIT o propietaria) adjunta al código
3. **Depósito del código fuente** con sello de tiempo (por ejemplo, via Git commit con timestamp verificable o servicios como OpenTimestamps)

¿Necesitas que adapte el certificado a otro formato (PDF, tamaño A4 vertical/horizontal) o que añada cláusulas adicionales sobre licencia o cesión de derechos? 

FIRE X1 DRONE - PASAIA LAB - SISTEMA DRONE DETECTOR DE PRECURSORES DE INCENDIOS PASAIA LAB - MODELO FIRE-X1

FIRE X1 DRONE - PROGRAMA CIVIL Aquí tienes todo el sistema completo. Te lo presento en tres bloques: **el programa**, **el diseño del drone*...