Added Gui (unfinished)

config into dataclass and enums
new Gui that includes settings
deleted GlobalVariables

small fixes (import, names...)
This commit is contained in:
2026-07-30 22:49:53 +02:00
parent b537677277
commit 9c31de3c38
13 changed files with 383 additions and 230 deletions
+184
View File
@@ -0,0 +1,184 @@
"""
MainWindow.py - Master Dashboard with Dynamic Input Selection
"""
import random
import time
import dearpygui.dearpygui as dpg
from config import cfg, BackendType
# Input State Tracking
input_config = {
"source": "Gamepad", # Options: "Gamepad", "GUI Sliders", "Random Walk"
"manual_vx": 0.0,
"manual_vy": 0.0,
"manual_omega": 0.0,
"random_interval": 2.0, # Change random vector every N seconds
"last_random_time": 0.0,
"random_vx": 0.0,
"random_vy": 0.0,
"random_omega": 0.0,
}
def create_parameter_gui(on_start_callback=None, on_stop_callback=None):
dpg.create_context()
dpg.create_viewport(title="JackBot Master Control Deck", width=460, height=800)
is_running = {"value": False}
def toggle_start(sender, app_data, user_data):
is_running["value"] = not is_running["value"]
if is_running["value"]:
dpg.configure_item("start_btn", label="STOP ROBOT")
dpg.configure_item("status_text", default_value="Status: RUNNING", color=(0, 255, 0))
dpg.configure_item("backend_combo", enabled=False)
if on_start_callback:
on_start_callback()
else:
dpg.configure_item("start_btn", label="START ROBOT")
dpg.configure_item("status_text", default_value="Status: STOPPED", color=(255, 100, 100))
dpg.configure_item("backend_combo", enabled=True)
if on_stop_callback:
on_stop_callback()
with dpg.window(label="Robot Control & Telemetry Deck", width=440, height=770, pos=(5, 5)):
# --- Execution Control ---
dpg.add_text("Control State", color=(0, 200, 255))
dpg.add_text("Status: STOPPED", tag="status_text", color=(255, 100, 100))
dpg.add_button(
label="START ROBOT",
tag="start_btn",
width=-1,
height=40,
callback=toggle_start
)
dpg.add_separator()
# --- Input Source Switcher ---
dpg.add_text("Input Controller Source", color=(0, 200, 255))
dpg.add_combo(
tag="input_source_combo",
label="Input Source",
items=["Gamepad", "GUI Sliders", "Random Walk"],
default_value=input_config["source"],
callback=lambda s, d: input_config.update({"source": d})
)
# Manual Sliders (Active when GUI Sliders selected)
dpg.add_slider_float(
label="Vx (Fwd/Bwd)",
default_value=0.0, min_value=-1.0, max_value=1.0,
callback=lambda s, d: input_config.update({"manual_vx": d})
)
dpg.add_slider_float(
label="Vy (Strafe)",
default_value=0.0, min_value=-1.0, max_value=1.0,
callback=lambda s, d: input_config.update({"manual_vy": d})
)
dpg.add_slider_float(
label="Omega (Turn)",
default_value=0.0, min_value=-1.0, max_value=1.0,
callback=lambda s, d: input_config.update({"manual_omega": d})
)
dpg.add_separator()
# --- Active Command Readouts ---
dpg.add_text("Active Command Output", color=(0, 200, 255))
dpg.add_text("Joysticks Connected: 0", tag="txt_joy_count")
dpg.add_text("Motion State: IDLE", tag="txt_motion_state", color=(200, 200, 200))
dpg.add_text("Active Vx : 0.00", tag="txt_vx")
dpg.add_text("Active Vy : 0.00", tag="txt_vy")
dpg.add_text("Active Omega: 0.00", tag="txt_omega")
dpg.add_separator()
# --- Backend Selection ---
dpg.add_text("Backend Selection", color=(0, 200, 255))
dpg.add_combo(
tag="backend_combo",
label="Target Backend",
items=[e.value for e in BackendType],
default_value=cfg.backend.value,
callback=lambda sender, data: setattr(cfg, 'backend', BackendType(data))
)
dpg.add_separator()
# --- Kinematics Adjustments ---
dpg.add_text("Gait & Kinematics", color=(0, 200, 255))
dpg.add_slider_float(
label="Step Height (m)",
default_value=cfg.step_height,
min_value=0.01, max_value=0.10, format="%.3f m",
callback=lambda sender, data: setattr(cfg, 'step_height', data)
)
dpg.add_slider_float(
label="Step Length (m)",
default_value=cfg.step_length,
min_value=0.01, max_value=0.10, format="%.3f m",
callback=lambda sender, data: setattr(cfg, 'step_length', data)
)
dpg.add_separator()
# --- Hardware Comms ---
dpg.add_text("Hardware Communications", color=(0, 200, 255))
dpg.add_input_text(label="ESP32 IP", default_value=cfg.esp32_ip, callback=lambda s, d: setattr(cfg, 'esp32_ip', d))
dpg.add_input_text(label="Serial Port", default_value=cfg.port, callback=lambda s, d: setattr(cfg, 'port', d))
dpg.setup_dearpygui()
dpg.show_viewport()
def resolve_active_command(gamepad_cmd: dict | None) -> dict:
"""Selects motion vector based on current active source in GUI."""
source = input_config["source"]
now = time.time()
if source == "GUI Sliders":
vx = input_config["manual_vx"]
vy = input_config["manual_vy"]
omega = input_config["manual_omega"]
joy_count = gamepad_cmd.get("joysticks_count", 0) if gamepad_cmd else 0
elif source == "Random Walk":
# Generate new random direction vector periodically
if now - input_config["last_random_time"] > input_config["random_interval"]:
input_config["random_vx"] = round(random.uniform(-1.0, 1.0), 2)
input_config["random_vy"] = round(random.uniform(-1.0, 1.0), 2)
input_config["random_omega"] = round(random.uniform(-1.0, 1.0), 2)
input_config["last_random_time"] = now
vx = input_config["random_vx"]
vy = input_config["random_vy"]
omega = input_config["random_omega"]
joy_count = gamepad_cmd.get("joysticks_count", 0) if gamepad_cmd else 0
else: # "Gamepad"
if gamepad_cmd:
vx, vy, omega = gamepad_cmd.get("dirmov", [0.0, 0.0, 0.0])
joy_count = gamepad_cmd.get("joysticks_count", 0)
else:
vx, vy, omega, joy_count = 0.0, 0.0, 0.0, 0
state = "walking" if (vx != 0.0 or vy != 0.0 or omega != 0.0) else "idle"
# Update GUI Labels
if dpg.is_dearpygui_running():
dpg.set_value("txt_joy_count", f"Joysticks Connected: {joy_count}")
dpg.set_value("txt_motion_state", f"Motion State: {state.upper()} ({source})")
dpg.set_value("txt_vx", f"Active Vx : {vx:>6.2f}")
dpg.set_value("txt_vy", f"Active Vy : {vy:>6.2f}")
dpg.set_value("txt_omega", f"Active Omega: {omega:>6.2f}")
return {
"state": state,
"dirmov": [vx, vy, omega]
}
def render_gui_frame():
if dpg.is_dearpygui_running():
dpg.render_dearpygui_frame()
def stop_gui():
dpg.destroy_context()