import tkinter as tk from tkinter import ttk # --- Conversion functions --- def nm_to_kgcm(tau_nm): return tau_nm * 10.197 # --- Torque calculation function --- def calculate(): # Get user inputs mass_total = float(mass_total_var.get()) legs_supporting = int(legs_supporting_var.get()) g = 9.81 coxa_len = float(coxa_len_var.get()) femur_len = float(femur_len_var.get()) tibia_len = float(tibia_len_var.get()) safety_factor = float(safety_factor_var.get()) servo_torque_max = float(servo_torque_max_var.get()) # Derived values mass_per_leg = mass_total / legs_supporting force_per_leg = mass_per_leg * g # Torques (Nm) tau_tibia = force_per_leg * tibia_len tau_femur = force_per_leg * (femur_len + tibia_len) tau_coxa = force_per_leg * coxa_len # Apply safety factor tau_tibia_req = tau_tibia * safety_factor tau_femur_req = tau_femur * safety_factor tau_coxa_req = tau_coxa * safety_factor # Convert to kg·cm coxa_kgcm = nm_to_kgcm(tau_coxa) femur_kgcm = nm_to_kgcm(tau_femur) tibia_kgcm = nm_to_kgcm(tau_tibia) coxa_kgcm_req = nm_to_kgcm(tau_coxa_req) femur_kgcm_req = nm_to_kgcm(tau_femur_req) tibia_kgcm_req = nm_to_kgcm(tau_tibia_req) # Update info labels info_label.config( text=( f"Mass per leg: {mass_per_leg:.3f} kg\n" f"Force per leg: {force_per_leg:.2f} N\n" f"Servo max torque: {servo_torque_max:.2f} kg·cm\n" f"Safety Factor: x{safety_factor:.2f}" ) ) # Update progress bars update_bar(coxa_bar, coxa_val, coxa_kgcm, servo_torque_max) update_bar(femur_bar, femur_val, femur_kgcm, servo_torque_max) update_bar(tibia_bar, tibia_val, tibia_kgcm, servo_torque_max) update_bar(coxa_bar_req, coxa_val_req, coxa_kgcm_req, servo_torque_max) update_bar(femur_bar_req, femur_val_req, femur_kgcm_req, servo_torque_max) update_bar(tibia_bar_req, tibia_val_req, tibia_kgcm_req, servo_torque_max) def update_bar(bar, label, value, limit): ratio = min(value / limit, 1.0) percent = (value / limit) * 100 bar["value"] = percent if percent <= 100 else 100 label.config(text=f"{value:.2f} / {limit:.2f} kg·cm") if value <= limit: bar.configure(style="Green.Horizontal.TProgressbar") else: bar.configure(style="Red.Horizontal.TProgressbar") # --- Tkinter GUI --- root = tk.Tk() root.title("Hexapod Torque Estimator (Live)") root.geometry("700x700") root.resizable(False, False) mainframe = ttk.Frame(root, padding=10) mainframe.pack(fill="both", expand=True) # Progress bar styles style = ttk.Style(root) style.theme_use("clam") style.configure("Green.Horizontal.TProgressbar", troughcolor="#333", background="#4CAF50") style.configure("Red.Horizontal.TProgressbar", troughcolor="#333", background="#F44336") # Input variables mass_total_var = tk.DoubleVar(value=1.08) legs_supporting_var = tk.IntVar(value=3) coxa_len_var = tk.DoubleVar(value=0.056) femur_len_var = tk.DoubleVar(value=0.072) tibia_len_var = tk.DoubleVar(value=0.07) safety_factor_var = tk.DoubleVar(value=4.5) servo_torque_max_var = tk.DoubleVar(value=2.3) # --- Layout --- def add_input(label, variable, from_, to, step=0.01): frame = ttk.Frame(mainframe) frame.pack(fill="x", pady=3) ttk.Label(frame, text=label, width=25).pack(side="left") entry = ttk.Entry(frame, textvariable=variable, width=8) entry.pack(side="left") scale = ttk.Scale(frame, variable=variable, from_=from_, to=to, command=lambda e: calculate()) scale.pack(side="left", fill="x", expand=True, padx=10) return entry add_input("Total Mass [kg]", mass_total_var, 0.1, 5.0) # Integer spinbox for legs supporting frame = ttk.Frame(mainframe) frame.pack(fill="x", pady=3) ttk.Label(frame, text="Legs Supporting", width=25).pack(side="left") spin = ttk.Spinbox(frame, from_=1, to=6, textvariable=legs_supporting_var, width=8, command=calculate) spin.pack(side="left") add_input("Coxa Length [m]", coxa_len_var, 0.03, 0.1) add_input("Femur Length [m]", femur_len_var, 0.03, 0.15) add_input("Tibia Length [m]", tibia_len_var, 0.03, 0.15) add_input("Safety Factor", safety_factor_var, 1.0, 3.0) add_input("Servo Torque Max [kg·cm]", servo_torque_max_var, 1.0, 5.0) # Info label info_label = ttk.Label(mainframe, text="", justify="left", font=("Courier", 10)) info_label.pack(pady=10) # Function to create a labeled progress bar def add_progress(label_text): frame = ttk.Frame(mainframe) frame.pack(fill="x", pady=3) ttk.Label(frame, text=label_text, width=10).pack(side="left") bar = ttk.Progressbar(frame, length=400, maximum=100) bar.pack(side="left", padx=5) val_label = ttk.Label(frame, width=20, anchor="w") val_label.pack(side="left") return bar, val_label # --- Without Safety Factor --- ttk.Label(mainframe, text="Without Safety Factor", font=("Helvetica", 11, "bold")).pack(pady=(15, 3)) coxa_bar, coxa_val = add_progress("Coxa") femur_bar, femur_val = add_progress("Femur") tibia_bar, tibia_val = add_progress("Tibia") # --- With Safety Factor --- ttk.Label(mainframe, text="With Safety Factor", font=("Helvetica", 11, "bold")).pack(pady=(15, 3)) coxa_bar_req, coxa_val_req = add_progress("Coxa") femur_bar_req, femur_val_req = add_progress("Femur") tibia_bar_req, tibia_val_req = add_progress("Tibia") # Auto-update on variable changes for var in [mass_total_var, legs_supporting_var, coxa_len_var, femur_len_var, tibia_len_var, safety_factor_var, servo_torque_max_var]: var.trace_add("write", lambda *args: calculate()) # Initial calculation calculate() root.mainloop()