mirror of
https://github.com/adrigongv23/G26---Telemetry-Software.git
synced 2026-08-25 03:23:17 +02:00
Prueba inicial rpm y bateria añadida
This commit is contained in:
parent
aacfd2f6c3
commit
b60f47cfb6
2 changed files with 142 additions and 62 deletions
|
|
@ -3,27 +3,40 @@ import time
|
|||
import math
|
||||
import random
|
||||
|
||||
# --- CONFIGURACIÓN ---
|
||||
UDP_IP = "127.0.0.1"
|
||||
# --- CONFIGURACIÓN DE RED ---
|
||||
UDP_IP = "127.0.0.1" # Enviamos a nuestro propio PC (Localhost)
|
||||
UDP_PORT = 4210
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
print(f"--- SIMULADOR DE COCHE G26 ---")
|
||||
print(f"Enviando datos falsos a {UDP_IP}:{UDP_PORT}")
|
||||
print("--- SIMULADOR G26 INICIADO ---")
|
||||
print("Formato de envío: ECT | RPM | BATT")
|
||||
print("Simulando batería bajando de 20V a 0V...")
|
||||
|
||||
t = 0
|
||||
batt = 20.0 # La batería empieza al máximo
|
||||
|
||||
while True:
|
||||
# Generar una temperatura que sube y baja mucho para probar todos los colores
|
||||
# Oscilará entre 40ºC y 120ºC
|
||||
ect = 80 + (40 * math.sin(t / 10.0)) + random.uniform(-0.5, 0.5)
|
||||
# 1. Simular Temperatura (ECT) - Oscila entre 80 y 90
|
||||
ect = 85 + (5 * math.sin(t / 5.0)) + random.uniform(-0.5, 0.5)
|
||||
|
||||
# Enviar solo el número
|
||||
mensaje = f"{ect:.2f}"
|
||||
# 2. Simular RPM - Acelerones entre 0 y 15000 RPM
|
||||
# Usamos valor absoluto del seno para simular que pisa el acelerador y suelta
|
||||
rpm = abs(15000 * math.sin(t / 2.0))
|
||||
|
||||
sock.sendto(mensaje.encode(), (UDP_IP, UDP_PORT))
|
||||
# 3. Simular Batería - Baja progresivamente
|
||||
batt -= 0.05 # Restamos un poco de voltaje en cada ciclo
|
||||
if batt < 0:
|
||||
batt = 20.0 # Si llega a 0, reiniciamos a 20V para que el test continúe
|
||||
|
||||
# 4. Empaquetar el mensaje (3 datos separados por '|')
|
||||
mensaje = f"{ect:.1f}|{int(rpm)}|{batt:.1f}"
|
||||
|
||||
print(f"Simulando: {mensaje} °C")
|
||||
# 5. Enviar por UDP
|
||||
sock.sendto(mensaje.encode('utf-8'), (UDP_IP, UDP_PORT))
|
||||
|
||||
# Imprimir en consola para confirmar visualmente
|
||||
print(f"Enviando -> {mensaje}")
|
||||
|
||||
t += 0.1
|
||||
time.sleep(0.05)
|
||||
time.sleep(0.05) # Espera 50 milisegundos (20 veces por segundo)
|
||||
|
|
@ -1,31 +1,36 @@
|
|||
import socket
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.animation as animation
|
||||
from matplotlib.gridspec import GridSpec
|
||||
from collections import deque
|
||||
import time
|
||||
import numpy as np
|
||||
from datetime import datetime
|
||||
|
||||
# --- CONFIGURACIÓN ---
|
||||
UDP_IP = "0.0.0.0" # Escuchamos en Todas las interfaces posibles (WiFi, Ethernet...)
|
||||
UDP_PORT = 4210 # Mismo puerto que usamos para la ESP32
|
||||
MAX_PUNTOS = 200 # Vamos a mostrar en la gráfica los últimos 200 datos
|
||||
TIMEOUT_SEG = 1.5 # Para ver si existe desconexión
|
||||
|
||||
# --- CONFIGURACIÓN VISUAL ---
|
||||
MAX_PUNTOS = 200 # Vamos a mostrar en la gráfica los últimos 200 datos
|
||||
MAX_RPM = 15000 # Límite máximo del velocímetro
|
||||
MIN_BATT = 0.0 # Mínimo voltaje para la gráfica
|
||||
MAX_BATT = 20.0 # Máximo voltaje para la gráfica
|
||||
|
||||
# Cola de datos
|
||||
data_ect = deque([0]*MAX_PUNTOS, maxlen=MAX_PUNTOS)
|
||||
|
||||
#Ocultamos estos valores ya que por el momento únicamente vamos a trabajar con la temperatura
|
||||
#data_rpm = deque([0]*MAX_PUNTOS, maxlen=MAX_PUNTOS)
|
||||
#data_bat = deque([0]*MAX_PUNTOS, maxlen=MAX_PUNTOS)
|
||||
# Para controlar si existe una desconexión de envio de paquetes
|
||||
ultimo_tiempo_dato = time.time()
|
||||
|
||||
# Configuración del socket UDP
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.bind((UDP_IP, UDP_PORT))
|
||||
sock.setblocking(False)
|
||||
|
||||
# --- DISEÑO GRÁFICO ---
|
||||
# --- DISEÑO DEL DASHBOARD ---
|
||||
plt.style.use('dark_background')
|
||||
fig, ax1 = plt.subplots(figsize=(10, 6)) # Usaremos una única ventana grande
|
||||
fig = plt.figure(figsize=(12, 8))
|
||||
|
||||
# Título principal + RELOJ
|
||||
fig.canvas.manager.set_window_title('G26 Telemetry - Monitor de Temperatura')
|
||||
|
|
@ -34,72 +39,134 @@ fig.suptitle('GADES TELEMETRY SYSTEM', fontsize=16, fontweight='bold', color='wh
|
|||
# Reloj en la esquina superior derecha
|
||||
txt_reloj = fig.text(0.85, 0.95, '--:--:--', fontsize=12, color='white', fontweight='bold')
|
||||
|
||||
# Configuración de la línea (empieza en blanco pero cambiará)
|
||||
line_ect, = ax1.plot([], [], color='white', lw=3)
|
||||
ax1.set_ylabel('Temperatura (°C)', fontsize=14)
|
||||
ax1.set_ylim(0, 130) # Rango de temperatura (0 a 130 grados)
|
||||
ax1.grid(True, alpha=0.3, linestyle='--')
|
||||
# Sistema de Grid (2 filas, 2 columnas)
|
||||
gs = GridSpec(2, 2, height_ratios=[1, 1])
|
||||
|
||||
# --- 1. GRÁFICA DE TEMPERATURA ---
|
||||
ax_ect = fig.add_subplot(gs[0, :])
|
||||
line_ect, = ax_ect.plot([], [], color='white', lw=3)
|
||||
ax_ect.set_ylabel('Temperatura (°C)', fontsize=14)
|
||||
ax_ect.set_ylim(0, 130) # Rango de temperatura (0 a 130 grados)
|
||||
ax_ect.grid(True, alpha=0.3, linestyle='--')
|
||||
|
||||
# Caja de texto con el valor actual
|
||||
props = dict(boxstyle='round', facecolor='black', alpha=0.8, edgecolor='white')
|
||||
txt_ect = ax1.text(0.02, 0.90, 'ESPERANDO...', transform=ax1.transAxes,
|
||||
txt_ect = ax_ect.text(0.02, 0.85, 'ESPERANDO...', transform=ax_ect.transAxes,
|
||||
fontsize=16, color='white', fontweight='bold', bbox=props)
|
||||
|
||||
#Para controlar si existe una desconexión de envio de paquetes
|
||||
ultimo_tiempo_dato = time.time()
|
||||
# --- 2. VELOCÍMETRO RPM (Fila inferior, Izquierda) ---
|
||||
ax_rpm = fig.add_subplot(gs[1, 0], projection='polar')
|
||||
ax_rpm.set_thetamin(0)
|
||||
ax_rpm.set_thetamax(180)
|
||||
ax_rpm.set_theta_zero_location("W") # El 0 empieza a la izquierda
|
||||
ax_rpm.set_theta_direction(-1) # Gira en sentido horario
|
||||
ax_rpm.set_xticklabels([]) # Quitar números del borde
|
||||
ax_rpm.set_yticklabels([])
|
||||
ax_rpm.grid(False)
|
||||
|
||||
# Arco gris de fondo
|
||||
theta_bg = np.linspace(0, np.pi, 100)
|
||||
ax_rpm.plot(theta_bg, np.ones_like(theta_bg), color='#444444', lw=8)
|
||||
|
||||
# Arco rojo de límite (12000 a 15000 RPM)
|
||||
theta_red = np.linspace((12000/MAX_RPM)*np.pi, np.pi, 50)
|
||||
ax_rpm.plot(theta_red, np.ones_like(theta_red), color='red', lw=8)
|
||||
|
||||
# Aguja y texto RPM
|
||||
needle, = ax_rpm.plot([0, 0], [0, 0.9], color='white', lw=4)
|
||||
txt_rpm = ax_rpm.text(0.5, 0.1, 'RPM: --', transform=ax_rpm.transAxes, ha='center', fontsize=20, fontweight='bold')
|
||||
|
||||
# --- 3. BARRA DE BATERÍA (Fila inferior, Derecha) ---
|
||||
ax_batt = fig.add_subplot(gs[1, 1])
|
||||
ax_batt.set_xlim(MIN_BATT, MAX_BATT)
|
||||
ax_batt.set_ylim(-0.5, 0.5)
|
||||
ax_batt.set_yticks([]) # Quitar eje Y
|
||||
ax_batt.set_xlabel('Voltaje (V)', fontsize=12)
|
||||
|
||||
# Contorno de la batería
|
||||
borde = plt.Rectangle((MIN_BATT, -0.3), MAX_BATT-MIN_BATT, 0.6, fill=False, edgecolor='white', lw=2)
|
||||
ax_batt.add_patch(borde)
|
||||
|
||||
# Barra interior amarilla/verde/roja
|
||||
bar_batt = ax_batt.barh(0, 0, left=MIN_BATT, height=0.5, color='green', align='center')[0]
|
||||
txt_batt = ax_batt.text(0.5, 0.8, 'BATT: -- V', transform=ax_batt.transAxes, ha='center', fontsize=18, fontweight='bold')
|
||||
|
||||
def get_color(temp):
|
||||
if temp > 105:
|
||||
return '#ff3333' # ROJO (Peligro)
|
||||
elif temp >= 95:
|
||||
return '#ffff33' # AMARILLO (Precaución)
|
||||
elif temp >= 65:
|
||||
return '#33ff33' # VERDE (Ok)
|
||||
else:
|
||||
return '#33ffff' # AZUL (Frío)
|
||||
|
||||
def update(frame):
|
||||
global ultimo_tiempo_dato # <--- ¡VITAL! Para poder modificar la variable global
|
||||
|
||||
# 1. Actualizar el Reloj con la hora del PC
|
||||
ahora = datetime.now().strftime("%H:%M:%S")
|
||||
txt_reloj.set_text(f"HORA: {ahora}")
|
||||
|
||||
try:
|
||||
while True:
|
||||
data, addr = sock.recvfrom(1024)
|
||||
msg = data.decode('utf-8')
|
||||
# partes = msg.split('|')
|
||||
partes = msg.split('|')
|
||||
|
||||
try:
|
||||
val_ect = float(msg) # Convertimos texto a número
|
||||
if len(partes) == 3:
|
||||
val_ect = float(partes[0])
|
||||
val_rpm = float(partes[1])
|
||||
val_batt = float(partes[2])
|
||||
|
||||
ultimo_tiempo_dato = time.time() # Reiniciar Watchdog
|
||||
|
||||
data_ect.append(val_ect) # Guardamos el dato
|
||||
ultimo_tiempo_dato = time.time() # Reiniciamos el contador ya que ha llegado un nuevo dato
|
||||
# 1. Actualizar ECT
|
||||
data_ect.append(val_ect)
|
||||
txt_ect.set_text(f"ECT: {val_ect:.1f} °C")
|
||||
txt_ect.set_color('cyan')
|
||||
|
||||
color_actual = get_color(val_ect) # Para que el valor cambie de color segun la temepratura
|
||||
txt_ect.set_text(f"TEMP: {val_ect: .1f} °C")
|
||||
txt_ect.set_color(color_actual)
|
||||
|
||||
except ValueError:
|
||||
print(f"Error de formato: {msg}")
|
||||
# 2. Actualizar RPM
|
||||
val_rpm = max(0, min(MAX_RPM, val_rpm))
|
||||
angulo_rad = (val_rpm / MAX_RPM) * np.pi
|
||||
needle.set_data([angulo_rad, angulo_rad], [0, 0.9])
|
||||
txt_rpm.set_text(f"RPM: {int(val_rpm)}")
|
||||
|
||||
if val_rpm > 12000: # Zona roja a partir de 12000
|
||||
txt_rpm.set_color('red')
|
||||
needle.set_color('red')
|
||||
else:
|
||||
txt_rpm.set_color('white')
|
||||
needle.set_color('white')
|
||||
|
||||
# 3. Actualizar Batería (Progresión visual 0V a 20V)
|
||||
txt_batt.set_text(f"BATT: {val_batt:.1f} V")
|
||||
ancho = max(0, min(MAX_BATT - MIN_BATT, val_batt - MIN_BATT))
|
||||
bar_batt.set_width(ancho)
|
||||
|
||||
# Colores adaptados para coche (Avisos de voltaje bajo)
|
||||
if val_batt < 11.5:
|
||||
bar_batt.set_color('red')
|
||||
elif val_batt < 12.5:
|
||||
bar_batt.set_color('yellow')
|
||||
else:
|
||||
bar_batt.set_color('green')
|
||||
|
||||
except BlockingIOError:
|
||||
pass
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
pass
|
||||
|
||||
# Comprobamos si el tiempo actual menos el último registro es mayor a 1.5s
|
||||
# --- WATCHDOG / TIMEOUT ---
|
||||
if (time.time() - ultimo_tiempo_dato) > TIMEOUT_SEG:
|
||||
data_ect.append(0) # Forzamos la gráfica a caer a 0
|
||||
txt_ect.set_text("COCHE APAGADO")
|
||||
txt_ect.set_color('#888888') # Color Gris
|
||||
txt_ect.get_bbox_patch().set_edgecolor('#888888')
|
||||
line_ect.set_color('#888888')
|
||||
|
||||
# Actualizamos la línea gráfica
|
||||
x_range = range(len(data_ect))
|
||||
line_ect.set_data(x_range, data_ect)
|
||||
ax1.set_xlim(0, max(len(data_ect), 1))
|
||||
|
||||
return line_ect, txt_ect, txt_reloj
|
||||
data_ect.append(0)
|
||||
txt_ect.set_text("ECT: DESCONECTADO")
|
||||
txt_ect.set_color('#555555')
|
||||
txt_rpm.set_text("RPM: 0")
|
||||
txt_rpm.set_color('#555555')
|
||||
needle.set_data([0, 0], [0, 0.9]) # Bajar aguja a 0
|
||||
needle.set_color('#555555')
|
||||
txt_batt.set_text("BATT: APAGADO")
|
||||
bar_batt.set_width(0)
|
||||
|
||||
ani = animation.FuncAnimation(fig, update, interval=20, blit=False, cache_frame_data=False)
|
||||
# Redibujar gráfica ECT
|
||||
line_ect.set_data(range(len(data_ect)), data_ect)
|
||||
ax_ect.set_xlim(0, max(len(data_ect), 1))
|
||||
|
||||
return line_ect, txt_ect, needle, txt_rpm, bar_batt, txt_batt
|
||||
|
||||
# Iniciar animación
|
||||
ani = animation.FuncAnimation(fig, update, interval=50, blit=False, cache_frame_data=False)
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
Loading…
Add table
Add a link
Reference in a new issue