Created
July 26, 2025 01:06
-
-
Save mateo08c/ac09e9ce42cefb3f30c133839a62a323 to your computer and use it in GitHub Desktop.
Python Script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import tkinter as tk | |
from tkinter import ttk | |
from tkinter.font import Font | |
import serial | |
import re | |
import threading | |
import math | |
from matplotlib.figure import Figure | |
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg | |
import sys | |
# --- Configuration --- | |
SERIAL_PORT = 'COM4' | |
BAUD_RATE = 115200 | |
REFRESH_RATE_MS = 30 | |
# La regex ne change pas, elle lit les données brutes envoyées par l'ESP | |
DATA_REGEX = re.compile( | |
r"\[RAW\]\s+" | |
r"x:(-?\d+)\s+" | |
r"y:(-?\d+)\s+" | |
r"d:([\d.]+)cm\s+" | |
r"a:([\d.]+)°\s+" | |
r"s:(-?[\d.]+)cm/s" | |
) | |
class DopplerApp: | |
def __init__(self, root): | |
self.root = root | |
self.root.title("Données Doppler (Unités Dynamiques)") | |
self.root.geometry("600x400") | |
self.root.protocol("WM_DELETE_WINDOW", self.on_closing) | |
self.radar_window = tk.Toplevel(self.root) | |
self.radar_window.title("Radar Doppler (Unités Dynamiques)") | |
self.radar_window.geometry("700x700") | |
self.radar_window.protocol("WM_DELETE_WINDOW", self.on_closing) | |
self.distance = tk.StringVar(value="--") | |
self.speed = tk.StringVar(value="--") | |
self.position = tk.StringVar(value="(--, --)") | |
self.last_detection = None | |
self.lock = threading.Lock() | |
self.is_running = True | |
large_font = Font(family="Helvetica", size=48, weight="bold") | |
label_font = Font(family="Helvetica", size=24) | |
data_frame = ttk.Frame(self.root, padding="20") | |
data_frame.pack(expand=True, fill="both") | |
ttk.Label(data_frame, text="Distance:", font=label_font).pack(pady=(10, 0)) | |
ttk.Label(data_frame, textvariable=self.distance, font=large_font, foreground="orange").pack() | |
ttk.Label(data_frame, text="Vitesse:", font=label_font).pack(pady=(10, 0)) | |
ttk.Label(data_frame, textvariable=self.speed, font=large_font, foreground="cyan").pack() | |
ttk.Label(data_frame, text="Position (X, Y):", font=label_font).pack(pady=(10, 0)) | |
ttk.Label(data_frame, textvariable=self.position, font=large_font, foreground="lightgreen").pack() | |
self.fig = Figure(figsize=(7, 7), dpi=100) | |
self.ax = self.fig.add_subplot(111, polar=True) | |
self.radar_canvas = FigureCanvasTkAgg(self.fig, master=self.radar_window) | |
self.radar_canvas.get_tk_widget().pack(expand=True, fill="both") | |
self.setup_radar() | |
self.status_var = tk.StringVar(value=f"Tentative de connexion au port {SERIAL_PORT}...") | |
status_bar = ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN, anchor="w") | |
status_bar.pack(side="bottom", fill="x") | |
self.serial_thread = threading.Thread(target=self.read_from_port, daemon=True) | |
self.serial_thread.start() | |
self.root.after(REFRESH_RATE_MS, self.update_gui_loop) | |
def setup_radar(self): | |
self.ax.set_theta_zero_location('N') | |
self.ax.set_theta_direction(-1) | |
self.ax.set_rlabel_position(90) | |
self.ax.set_title("Détection Radar (distances en cm)", va='bottom', fontsize=16) | |
self.ax.tick_params(labelsize=12) | |
self.detection_point, = self.ax.plot([], [], 'ro', markersize=15, alpha=0.75) | |
self.ax.set_ylim(0, 800) | |
self.fig.tight_layout() | |
def read_from_port(self): | |
while self.is_running: | |
try: | |
with serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) as ser: | |
self.root.after(0, lambda: self.status_var.set(f"Connecté à {SERIAL_PORT} @ {BAUD_RATE} bauds")) | |
while self.is_running: | |
line = ser.readline().decode('utf-8', errors='ignore').strip() | |
if line: | |
match = DATA_REGEX.match(line) | |
if match: | |
x, y, d, a, s = match.groups() | |
with self.lock: | |
# Les valeurs d, s sont en mm et mm/s | |
self.last_detection = { | |
'x': int(x), 'y': int(y), | |
'd': float(d), 'a': float(a), 's': float(s) | |
} | |
except serial.SerialException: | |
if self.is_running: | |
self.root.after(0, lambda: self.status_var.set( | |
f"Port {SERIAL_PORT} non trouvé. Nouvelle tentative...")) | |
threading.Event().wait(3) | |
def _format_distance(self, dist_mm): | |
if dist_mm >= 1000: # Plus de 1m | |
return f"{dist_mm / 1000.0:.2f} m" | |
elif dist_mm >= 10: # Entre 1cm et 1m | |
return f"{dist_mm / 10.0:.1f} cm" | |
else: # Moins de 1cm | |
return f"{dist_mm:.0f} mm" | |
def _format_speed(self, speed_mms): | |
abs_speed = abs(speed_mms) | |
if abs_speed >= 1000: # Plus de 1m/s | |
return f"{speed_mms / 1000.0:.2f} m/s" | |
elif abs_speed >= 10: # Entre 1cm/s et 1m/s | |
return f"{speed_mms / 10.0:.1f} cm/s" | |
else: # Moins de 1cm/s | |
return f"{speed_mms:.0f} mm/s" | |
def update_gui_loop(self): | |
current_detection = None | |
with self.lock: | |
if self.last_detection: | |
current_detection = self.last_detection | |
if current_detection: | |
dist_mm = current_detection['d'] | |
speed_mms = current_detection['s'] | |
# Mise à jour des labels avec les unités dynamiques | |
self.distance.set(self._format_distance(dist_mm)) | |
self.speed.set(self._format_speed(speed_mms)) | |
self.position.set(f"({current_detection['x']}, {current_detection['y']})") | |
# Le graphique radar utilisera toujours les cm pour la cohérence | |
distance_cm = dist_mm / 10.0 | |
angle_rad = math.radians(current_detection['a']) | |
self.detection_point.set_data([angle_rad], [distance_cm]) | |
current_max_r = self.ax.get_rmax() | |
if distance_cm > current_max_r: | |
self.ax.set_rmax(distance_cm * 1.2) | |
self.radar_canvas.draw() | |
if self.is_running: | |
self.root.after(REFRESH_RATE_MS, self.update_gui_loop) | |
def on_closing(self): | |
self.is_running = False | |
self.root.destroy() | |
sys.exit() | |
if __name__ == "__main__": | |
root = tk.Tk() | |
app = DopplerApp(root) | |
root.mainloop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment