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?




