mirror of
https://github.com/adrigongv23/G26---Telemetry-Software.git
synced 2026-08-25 19:43:16 +02:00
Actualización visual de la telemetria con velocidad y grafica acelerador freno
This commit is contained in:
parent
d3f2d1596e
commit
7c069efa14
2 changed files with 108 additions and 59 deletions
|
|
@ -28,11 +28,11 @@ while True:
|
|||
# Régimen siguiendo al acelerador, con algo de inercia
|
||||
rpm = 1200 + 12800 * (carga ** 0.7) + random.uniform(-120, 120)
|
||||
|
||||
# Marcha: sube con el régimen, 0 = punto muerto
|
||||
if rpm < 1500:
|
||||
marcha = 0
|
||||
else:
|
||||
marcha = min(6, 1 + int((rpm - 1500) / 2300))
|
||||
# Velocidad: correlada con el régimen (modelo simple para el simulador)
|
||||
velocidad = 15 + 105 * (carga ** 0.8) + random.uniform(-1.5, 1.5)
|
||||
|
||||
# Freno delantero: presión (bar). Frena al levantar el pie del acelerador
|
||||
freno_del = max(0.0, 45 * max(0.0, min(1.0, (6 - tps) / 6)) + random.uniform(-0.4, 0.4))
|
||||
|
||||
# Temperaturas: suben poco a poco y responden a la carga
|
||||
ect = 88 + 6 * math.sin(t / 20.0) + 4 * carga + random.uniform(-0.3, 0.3)
|
||||
|
|
@ -66,7 +66,8 @@ while True:
|
|||
'lambda': f'{lambda_val:.3f}',
|
||||
'lambda_obj': f'{lambda_obj:.3f}',
|
||||
'tps': f'{tps:.0f}',
|
||||
'marcha': f'{marcha}',
|
||||
'velocidad': f'{velocidad:.0f}',
|
||||
'freno_del': f'{freno_del:.1f}',
|
||||
}
|
||||
mensaje = ';'.join(f'{clave}={valor}' for clave, valor in campos.items())
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import csv
|
|||
import matplotlib.pyplot as plt
|
||||
import matplotlib.animation as animation
|
||||
from matplotlib.gridspec import GridSpec
|
||||
from matplotlib.patches import Rectangle
|
||||
from matplotlib.patches import Rectangle, Polygon
|
||||
from matplotlib.lines import Line2D
|
||||
from matplotlib.colors import to_rgb
|
||||
from collections import deque
|
||||
|
|
@ -28,8 +28,8 @@ MAX_PUNTOS = FRECUENCIA_HZ * VENTANA_SEG
|
|||
# 1. "87.3|9200|14.2" -> ECT | RPM | BATERÍA
|
||||
#
|
||||
# 2. Nuevo (clave-valor, para cuando el firmware envíe el resto de canales):
|
||||
# "ect=87.3;rpm=9200;vbatt=14.2;pcomb=3.6;taceite=104;paceite=4.2;
|
||||
# map=98;lambda=0.88;lambda_obj=0.88;tps=45;marcha=3"
|
||||
# "ect=87.3;rpm=9200;vbatt=14.2;velocidad=64;tps=45;freno_del=8.5;
|
||||
# pcomb=3.6;taceite=104;paceite=4.2;map=98;lambda=0.88;lambda_obj=0.88"
|
||||
CLAVES_LEGADO = ('ect', 'rpm', 'vbatt')
|
||||
|
||||
# --- PALETA (tomada del logo oficial del equipo) ---
|
||||
|
|
@ -49,8 +49,12 @@ APAGADO = '#18213A' # Segmento / relleno inactivo
|
|||
MAX_RPM = 13000 # Fondo de escala del indicador
|
||||
RPM_CORTE = 12000 # Zona roja / corte de inyección
|
||||
|
||||
# --- MARCHAS ---
|
||||
VALOR_NEUTRAL = 0 # Valor con el que la ECU codifica el punto muerto
|
||||
# --- PEDALES ---
|
||||
VENTANA_PEDALES_SEG = 7 # Segundos visibles en la traza de pedales
|
||||
PUNTOS_PEDALES = FRECUENCIA_HZ * VENTANA_PEDALES_SEG
|
||||
# El sensor de freno es de PRESIÓN (bar). Este es el valor que se dibuja como el
|
||||
# 100 % de la traza. AJUSTAR cuando se mida en pista la frenada más fuerte.
|
||||
FRENO_PRESION_MAX = 50.0
|
||||
|
||||
# --- DEFINICIÓN DE CANALES ---
|
||||
# Cada canal declara su rango visible, sus zonas de color y una referencia
|
||||
|
|
@ -91,6 +95,21 @@ CANALES = {
|
|||
etiqueta='TPS', descripcion='ACELERADOR', unidad='%',
|
||||
vmin=0, vmax=100, decimales=0, referencia=None,
|
||||
zonas=[(float('inf'), AZUL)]),
|
||||
# Frenos: sensores de PRESIÓN. Se guardan en bar (real) y en la traza se
|
||||
# normalizan a 0-100 % contra FRENO_PRESION_MAX. Solo el delantero está
|
||||
# instalado; el trasero queda declarado a la espera de montarse.
|
||||
'freno_del': dict(
|
||||
etiqueta='FRENO DEL.', descripcion='PRESIÓN FRENO DELANTERO', unidad='bar',
|
||||
vmin=0, vmax=FRENO_PRESION_MAX, decimales=1, referencia=None,
|
||||
zonas=[(float('inf'), ROJO)]),
|
||||
'freno_tra': dict(
|
||||
etiqueta='FRENO TRA.', descripcion='PRESIÓN FRENO TRASERO', unidad='bar',
|
||||
vmin=0, vmax=FRENO_PRESION_MAX, decimales=1, referencia=None,
|
||||
zonas=[(float('inf'), ROJO)]),
|
||||
'velocidad': dict(
|
||||
etiqueta='VELOCIDAD', descripcion='VELOCIDAD', unidad='km/h',
|
||||
vmin=0, vmax=160, decimales=0, referencia=None,
|
||||
zonas=[(float('inf'), AZUL)]),
|
||||
'rpm': dict(
|
||||
etiqueta='RPM', descripcion='RÉGIMEN DE MOTOR', unidad='',
|
||||
vmin=0, vmax=MAX_RPM, decimales=0, referencia=None,
|
||||
|
|
@ -141,7 +160,8 @@ aviso_pie = ''
|
|||
aviso_hasta = 0.0
|
||||
|
||||
# Orden de las columnas del CSV de sesión
|
||||
COLUMNAS_CSV = ['ect', 'rpm', 'vbatt', 'pcomb', 'taceite', 'paceite', 'map', 'lambda', 'tps', 'marcha']
|
||||
COLUMNAS_CSV = ['ect', 'rpm', 'velocidad', 'vbatt', 'tps', 'freno_del', 'freno_tra',
|
||||
'pcomb', 'taceite', 'paceite', 'map', 'lambda']
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.bind((UDP_IP, UDP_PORT))
|
||||
|
|
@ -218,7 +238,7 @@ def formatear(clave, valor):
|
|||
|
||||
def valor_csv(clave):
|
||||
"""Valor para el fichero de sesión: sin separador de millares, que rompería
|
||||
el CSV, y con los decimales propios del canal (RPM y marcha son enteros)."""
|
||||
el CSV, y con los decimales propios del canal (RPM y velocidad son enteros)."""
|
||||
valor = ultima_lectura.get(clave)
|
||||
if valor is None:
|
||||
return ''
|
||||
|
|
@ -226,13 +246,6 @@ def valor_csv(clave):
|
|||
return f'{valor:.{decimales}f}'
|
||||
|
||||
|
||||
def formatear_marcha(valor):
|
||||
if valor is None:
|
||||
return '-'
|
||||
valor = int(round(valor))
|
||||
return 'N' if valor == VALOR_NEUTRAL else str(valor)
|
||||
|
||||
|
||||
def formato_tiempo(segundos):
|
||||
if segundos is None:
|
||||
return '--:--'
|
||||
|
|
@ -349,8 +362,8 @@ fig.text(0.50, 0.017, 'R grabar S captura 1-7 gráfica F
|
|||
fontsize=8.5, color=TXT_DIM, ha='center', va='center')
|
||||
txt_fichero = fig.text(0.975, 0.017, '', fontsize=8.5, color=TXT_DIM, ha='right', va='center')
|
||||
|
||||
# --- BANDA A: LO QUE HACE EL PILOTO (RPM + MARCHA + ACELERADOR) ---
|
||||
gs_a = GridSpec(1, 3, width_ratios=[3.0, 0.72, 0.85],
|
||||
# --- BANDA A: LO QUE HACE EL PILOTO (RPM + VELOCIDAD + PEDALES) ---
|
||||
gs_a = GridSpec(1, 3, width_ratios=[2.6, 0.8, 1.7],
|
||||
left=0.035, right=0.975, top=0.893, bottom=0.712, wspace=0.030)
|
||||
|
||||
# A1. Luces de cambio
|
||||
|
|
@ -385,26 +398,58 @@ ax_rpm.text(2, 0.88, 'RPM', fontsize=9, color=TXT_DIM, va='center')
|
|||
txt_rpm = ax_rpm.text(98, 0.55, '--', fontsize=30, fontweight='bold', color=TXT_DIM,
|
||||
ha='right', va='center')
|
||||
|
||||
# A2. Marcha: el dato más glanceable de un panel, por eso va a tamaño máximo
|
||||
ax_marcha = fig.add_subplot(gs_a[0, 1])
|
||||
preparar_panel(ax_marcha, AZUL)
|
||||
ax_marcha.text(0.5, 0.88, 'MARCHA', fontsize=9, color=TXT_DIM, ha='center', va='center')
|
||||
txt_marcha = ax_marcha.text(0.5, 0.42, '-', fontsize=62, fontweight='bold', color=TXT_DIM,
|
||||
ha='center', va='center')
|
||||
# A2. Velocidad: número grande, hereda el hueco glanceable que dejó la marcha
|
||||
ax_vel = fig.add_subplot(gs_a[0, 1])
|
||||
preparar_panel(ax_vel, AZUL)
|
||||
ax_vel.text(0.5, 0.86, 'VELOCIDAD', fontsize=9, color=TXT_DIM, ha='center', va='center')
|
||||
txt_vel = ax_vel.text(0.5, 0.45, '--', fontsize=54, fontweight='bold', color=TXT_DIM,
|
||||
ha='center', va='center')
|
||||
ax_vel.text(0.5, 0.13, 'km/h', fontsize=12, color=TXT_DIM, ha='center', va='center')
|
||||
|
||||
# A3. Acelerador
|
||||
ax_tps = fig.add_subplot(gs_a[0, 2])
|
||||
preparar_panel(ax_tps, AZUL)
|
||||
ax_tps.text(0.09, 0.86, 'TPS', fontsize=9, color=TXT_DIM, va='center')
|
||||
txt_tps = ax_tps.text(0.93, 0.84, '--', fontsize=20, fontweight='bold', color=TXT_DIM,
|
||||
ha='right', va='center')
|
||||
X_TPS, ANCHO_TPS, Y_TPS, ALTO_TPS = 0.09, 0.84, 0.30, 0.26
|
||||
ax_tps.add_patch(Rectangle((X_TPS, Y_TPS), ANCHO_TPS, ALTO_TPS, facecolor=APAGADO))
|
||||
bar_tps = Rectangle((X_TPS, Y_TPS), 0, ALTO_TPS, facecolor=AZUL)
|
||||
ax_tps.add_patch(bar_tps)
|
||||
for pct in (0, 50, 100):
|
||||
x = X_TPS + ANCHO_TPS * pct / 100
|
||||
ax_tps.text(x, 0.22, f'{pct}', fontsize=7, color=TXT_DIM, ha='center', va='top')
|
||||
# A3. Traza de pedales: acelerador (verde) y freno (rojo) oscilando de 0 a 100 %,
|
||||
# como en la telemetría real. El freno es presión (bar) normalizada a % en pantalla.
|
||||
ax_ped = fig.add_subplot(gs_a[0, 2])
|
||||
ax_ped.set_facecolor(PANEL)
|
||||
for lado in ('top', 'right'):
|
||||
ax_ped.spines[lado].set_visible(False)
|
||||
for lado in ('bottom', 'left'):
|
||||
ax_ped.spines[lado].set_color(GRID)
|
||||
ax_ped.set_xlim(0, PUNTOS_PEDALES)
|
||||
ax_ped.set_ylim(0, 105)
|
||||
ax_ped.set_yticks([0, 50, 100])
|
||||
ax_ped.set_yticklabels(['0', '50', '100'], fontsize=7)
|
||||
ax_ped.set_xticks([0, PUNTOS_PEDALES / 2, PUNTOS_PEDALES])
|
||||
ax_ped.set_xticklabels([f'-{VENTANA_PEDALES_SEG:g} s'.replace('.', ','),
|
||||
f'-{VENTANA_PEDALES_SEG / 2:g} s'.replace('.', ','), 'ahora'], fontsize=7)
|
||||
ax_ped.tick_params(length=0, labelsize=7.5)
|
||||
ax_ped.grid(True, color=GRID, alpha=0.5, linestyle='--', lw=0.6, zorder=1)
|
||||
ax_ped.text(PUNTOS_PEDALES * 0.015, 99, 'PEDALES', fontsize=9, color=TXT_DIM, va='top', zorder=5)
|
||||
|
||||
fill_tps = Polygon([[0, 0], [0, 0]], closed=True, facecolor=VERDE, alpha=0.22,
|
||||
edgecolor='none', zorder=2)
|
||||
fill_freno = Polygon([[0, 0], [0, 0]], closed=True, facecolor=ROJO, alpha=0.20,
|
||||
edgecolor='none', zorder=2)
|
||||
ax_ped.add_patch(fill_tps)
|
||||
ax_ped.add_patch(fill_freno)
|
||||
line_tps, = ax_ped.plot([], [], color=VERDE, lw=2, zorder=4, solid_capstyle='round')
|
||||
line_freno, = ax_ped.plot([], [], color=ROJO, lw=2, zorder=3, solid_capstyle='round')
|
||||
_caja_ped = dict(facecolor=PANEL, alpha=0.65, edgecolor='none', boxstyle='square,pad=0.2')
|
||||
txt_ped_tps = ax_ped.text(PUNTOS_PEDALES * 0.985, 80, 'ACEL --', fontsize=10.5,
|
||||
fontweight='bold', color=VERDE, ha='right', va='center',
|
||||
zorder=6, bbox=_caja_ped)
|
||||
txt_ped_freno = ax_ped.text(PUNTOS_PEDALES * 0.985, 62, 'FRENO --', fontsize=10.5,
|
||||
fontweight='bold', color=ROJO, ha='right', va='center',
|
||||
zorder=6, bbox=_caja_ped)
|
||||
|
||||
|
||||
def area_pedales(xs, ys):
|
||||
"""Vértices del polígono relleno bajo una curva de pedal, saltándose los NaN
|
||||
(que aparecen al desconectar), para que el relleno no se rompa."""
|
||||
m = np.isfinite(ys)
|
||||
if not m.any():
|
||||
return [[0, 0], [0, 0]]
|
||||
xf, yf = xs[m], ys[m]
|
||||
return [(xf[0], 0)] + list(zip(xf, yf)) + [(xf[-1], 0)]
|
||||
|
||||
# --- BANDA B: CANAL CON FOCO (número grande + gráfica) ---
|
||||
gs_b = GridSpec(1, 2, width_ratios=[1, 3.3],
|
||||
|
|
@ -704,7 +749,7 @@ def update(frame):
|
|||
txt_hz.set_text('-- Hz')
|
||||
txt_hz.set_color(TXT_DIM)
|
||||
|
||||
# --- BANDA A: RPM, MARCHA, TPS ---
|
||||
# --- BANDA A: RPM, VELOCIDAD, PEDALES ---
|
||||
valor_rpm = ultima_lectura.get('rpm') if conectado else None
|
||||
if valor_rpm is not None:
|
||||
valor_rpm = max(0, min(MAX_RPM, valor_rpm))
|
||||
|
|
@ -726,25 +771,28 @@ def update(frame):
|
|||
txt_rpm.set_text('--')
|
||||
txt_rpm.set_color(TXT_DIM)
|
||||
|
||||
valor_marcha = ultima_lectura.get('marcha') if conectado else None
|
||||
txt_marcha.set_text(formatear_marcha(valor_marcha))
|
||||
if valor_marcha is None:
|
||||
txt_marcha.set_color(TXT_DIM)
|
||||
elif int(round(valor_marcha)) == VALOR_NEUTRAL:
|
||||
txt_marcha.set_color(VERDE)
|
||||
else:
|
||||
txt_marcha.set_color(TXT)
|
||||
# Velocidad: número grande
|
||||
valor_vel = ultima_lectura.get('velocidad') if conectado else None
|
||||
txt_vel.set_text(formatear('velocidad', valor_vel))
|
||||
txt_vel.set_color(TXT if valor_vel is not None else TXT_DIM)
|
||||
|
||||
valor_tps = ultima_lectura.get('tps') if conectado else None
|
||||
if valor_tps is not None:
|
||||
fraccion = min(max(valor_tps / 100.0, 0.0), 1.0)
|
||||
bar_tps.set_width(ANCHO_TPS * fraccion)
|
||||
txt_tps.set_text(f'{formatear("tps", valor_tps)} %')
|
||||
txt_tps.set_color(TXT)
|
||||
# Traza de pedales: acelerador (0-100 %) y freno (presión -> % de FRENO_PRESION_MAX)
|
||||
serie_tps = np.array(historial['tps'], dtype=float)[-PUNTOS_PEDALES:]
|
||||
serie_freno = np.array(historial['freno_del'], dtype=float)[-PUNTOS_PEDALES:]
|
||||
freno_pct = np.clip(serie_freno / FRENO_PRESION_MAX * 100.0, 0, 100)
|
||||
xs_ped = np.arange(len(serie_tps), dtype=float)
|
||||
line_tps.set_data(xs_ped, serie_tps)
|
||||
line_freno.set_data(xs_ped, freno_pct)
|
||||
fill_tps.set_xy(area_pedales(xs_ped, serie_tps))
|
||||
fill_freno.set_xy(area_pedales(xs_ped, freno_pct))
|
||||
|
||||
val_tps = ultima_lectura.get('tps') if conectado else None
|
||||
val_freno = ultima_lectura.get('freno_del') if conectado else None
|
||||
txt_ped_tps.set_text(f'ACEL {int(round(val_tps))}%' if val_tps is not None else 'ACEL --')
|
||||
if val_freno is not None:
|
||||
txt_ped_freno.set_text(f'FRENO {int(round(min(100.0, val_freno / FRENO_PRESION_MAX * 100)))}%')
|
||||
else:
|
||||
bar_tps.set_width(0)
|
||||
txt_tps.set_text('--')
|
||||
txt_tps.set_color(TXT_DIM)
|
||||
txt_ped_freno.set_text('FRENO --')
|
||||
|
||||
# --- BANDA C: TARJETAS ---
|
||||
alarmas = []
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue