Added Gui (unfinished)
config into dataclass and enums new Gui that includes settings deleted GlobalVariables small fixes (import, names...)
This commit is contained in:
@@ -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()
|
||||
Reference in New Issue
Block a user