Skip to content

Instantly share code, notes, and snippets.

@mateo08c
Created July 26, 2025 01:06
Show Gist options
  • Save mateo08c/ac09e9ce42cefb3f30c133839a62a323 to your computer and use it in GitHub Desktop.
Save mateo08c/ac09e9ce42cefb3f30c133839a62a323 to your computer and use it in GitHub Desktop.
Python Script
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