Skip to content

Commit 2693fe0

Browse files
Added features for adding vehicle parameters for load transfer based planner and added more user warning/ success messages
1 parent 26c5edc commit 2693fe0

File tree

3 files changed

+146
-45
lines changed

3 files changed

+146
-45
lines changed

GUI_supporting_pages/deploy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ def next_page(self):
369369
args_json = json.dumps(self.controller.args_dict)
370370
# Path to the package in parent folder
371371

372-
dev_mode =True
372+
dev_mode =False
373373
if dev_mode == True:
374374
print('Running app in dev mode: Running koopman.py script')
375375
parent_dir = '/home/krovilab/Project-Varuna-RZR/Project-Varuna-MMPK-Package'

GUI_supporting_pages/planning_controls.py

Lines changed: 136 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -224,36 +224,6 @@ def __init__(self, parent, controller):
224224
self.update_ui_control_topic_select()
225225

226226

227-
# create radiobutton frame for training and test data
228-
self.planner_control_horizon_frame = ctk.CTkFrame(self)
229-
self.planner_control_horizon_frame.grid(row=1, column=3,columnspan=2, padx=(20, 20), pady=(20, 0), sticky="nsew")
230-
231-
# MPC Cost Label
232-
self.label_preview = ctk.CTkLabel(master=self.planner_control_horizon_frame, text="Planner-Controller Preview")
233-
self.label_preview.grid(row=0, column=0, padx=10, pady=10, sticky="w")
234-
235-
# Add Label: State Penalty
236-
self.label_mpc_horizon = ctk.CTkLabel(master=self.planner_control_horizon_frame, text="Prediction horizon for Model/Controller:")
237-
self.label_mpc_horizon.grid(row=1, column=0, padx=10, pady=10, sticky="w")
238-
239-
# Add Entry: State Penalty Entry Box
240-
self.entry_mpc_horizon = ctk.CTkEntry(master=self.planner_control_horizon_frame)
241-
self.entry_mpc_horizon.grid(row=1, column=1, padx=10, pady=10, sticky="w")
242-
243-
# Add Label: Control Action Penalty
244-
self.label_planner_horizon = ctk.CTkLabel(master=self.planner_control_horizon_frame, text="Prediction horizon for Motion Planner:")
245-
self.label_planner_horizon.grid(row=2, column=0, padx=10, pady=10, sticky="w")
246-
247-
# Add Entry: Control Action Penalty Entry Box
248-
self.entry_planner_horizon = ctk.CTkEntry(master=self.planner_control_horizon_frame)
249-
self.entry_planner_horizon.grid(row=2, column=1, padx=10, pady=10, sticky="w")
250-
251-
#Add a Button to trigger saving into the dictionary
252-
save_button = ctk.CTkButton(master=self.planner_control_horizon_frame, text="Apply", command=self.save_horizon_values)
253-
save_button.grid(row=3, column=1, pady=10)
254-
255-
256-
257227
self.appearance_mode_optionemenu.set("Dark")
258228
self.scaling_optionemenu.set("100%")
259229

@@ -266,7 +236,9 @@ def refresh(self):
266236
# if hasattr(self, 'imu_topic_dropdown'):
267237
# self.imu_topic_dropdown.grid_forget()
268238
# self.update_ui_rostopic_select(mmpk_type)
269-
self.update_ui_motion_planner_type(mmpk_type)
239+
self.planner_control_parameter_selection(mmpk_type)
240+
self.update_ui_load_transfer_parameters(mmpk_type)
241+
# self.update_ui_motion_planner_type(mmpk_type)
270242

271243
def change_appearance_mode_event(self, new_appearance_mode: str):
272244
ctk.set_appearance_mode(new_appearance_mode)
@@ -322,33 +294,122 @@ def update_ui_control_topic_select(self):
322294
values=self.available_topics,command=self.save_control_topic_steering)
323295
self.steering_topic_dropdown.grid(row=9, column=0, padx=(0, 10), pady=(10, 10), sticky="ew")
324296

325-
def update_ui_motion_planner_type(self,mmpk_type):
326-
# create radiobutton frame for type of planer
327-
self.planner_type_frame = ctk.CTkFrame(self)
328-
self.planner_type_frame.grid(row=2, column=3, columnspan=2, padx=(20, 20), pady=(20, 0), sticky="nsew")
297+
298+
'''Planner type and horizon selection'''
299+
def planner_control_parameter_selection(self,mmpk_type):
300+
self.planner_control_parameters_frame = ctk.CTkFrame(self)
301+
self.planner_control_parameters_frame.grid(row=1, column=3, columnspan=2, padx=(20, 20), pady=(20, 0),
302+
sticky="nsew")
303+
304+
# MPC Cost Label
305+
self.label_preview = ctk.CTkLabel(master=self.planner_control_parameters_frame,
306+
text="Planner-Controller Preview")
307+
self.label_preview.grid(row=0, column=0, padx=10, pady=10, sticky="w")
308+
309+
# Add Label: State Penalty
310+
self.label_mpc_horizon = ctk.CTkLabel(master=self.planner_control_parameters_frame,
311+
text="Prediction horizon for Model/Controller:")
312+
self.label_mpc_horizon.grid(row=1, column=0, padx=10, pady=10, sticky="w")
313+
314+
# Add Entry: State Penalty Entry Box
315+
self.entry_mpc_horizon = ctk.CTkEntry(master=self.planner_control_parameters_frame)
316+
self.entry_mpc_horizon.grid(row=1, column=1, padx=10, pady=10, sticky="w")
317+
318+
# Add Label: Control Action Penalty
319+
self.label_planner_horizon = ctk.CTkLabel(master=self.planner_control_parameters_frame,
320+
text="Prediction horizon for Motion Planner:")
321+
self.label_planner_horizon.grid(row=2, column=0, padx=10, pady=10, sticky="w")
322+
323+
# Add Entry: Control Action Penalty Entry Box
324+
self.entry_planner_horizon = ctk.CTkEntry(master=self.planner_control_parameters_frame)
325+
self.entry_planner_horizon.grid(row=2, column=1, padx=10, pady=10, sticky="w")
326+
327+
# Add a Button to trigger saving into the dictionary
328+
save_button = ctk.CTkButton(master=self.planner_control_parameters_frame, text="Apply",
329+
command=self.save_horizon_values)
330+
save_button.grid(row=3, column=1, pady=10)
329331

330332
# Planner Type Label
331-
self.label_planner_type = ctk.CTkLabel(master=self.planner_type_frame, text="Planner-Controller Preview")
332-
self.label_planner_type.grid(row=0, column=0, padx=10, pady=10, sticky="w")
333+
self.label_planner_type = ctk.CTkLabel(master=self.planner_control_parameters_frame, text="Motion Planner Type")
334+
self.label_planner_type.grid(row=4, column=0, padx=10, pady=10, sticky="w")
333335

334336
# Radio button to save planner_type
335337
self.radio_var_planner_type = tk.IntVar(value=0)
336338

337339
self.controller.args_dict['Planning_Controls']['Planner_type'] = 'Curvature_based'
338340

339341
# Curvature-based Reachability Planner radio button
340-
self.radio_button_curvature_planner = ctk.CTkRadioButton(master=self.planner_type_frame,
342+
self.radio_button_curvature_planner = ctk.CTkRadioButton(master=self.planner_control_parameters_frame,
341343
variable=self.radio_var_planner_type,
342-
value=0, text='Curvature-based Reachability Planner',command=self.save_planner_type)
343-
self.radio_button_curvature_planner.grid(row=1, column=0, pady=(5, 10), padx=(20, 10), sticky="w")
344+
value=0, text='Curvature-based Reachability Planner',
345+
command=self.save_planner_type)
346+
self.radio_button_curvature_planner.grid(row=5, column=0, pady=(5, 10), padx=(20, 10), sticky="w")
344347

345348
# Load-transfer based Reachability Planner radio button (only for 'Adaptive' type)
346349
if mmpk_type == 'Adaptive':
347-
self.radio_button_load_transfer_planner = ctk.CTkRadioButton(master=self.planner_type_frame,
350+
self.radio_button_load_transfer_planner = ctk.CTkRadioButton(master=self.planner_control_parameters_frame,
348351
variable=self.radio_var_planner_type,
349352
value=1,
350-
text='Load-transfer based Reachability Planner',command=self.save_planner_type)
351-
self.radio_button_load_transfer_planner.grid(row=2, column=0, pady=(5, 10), padx=(20, 10), sticky="w")
353+
text='Load-transfer based Reachability Planner',
354+
command=self.save_planner_type)
355+
self.radio_button_load_transfer_planner.grid(row=6, column=0, pady=(5, 10), padx=(20, 10), sticky="w")
356+
357+
self.planner_load_transfer_frame = ctk.CTkFrame(self)
358+
self.planner_load_transfer_frame.grid(row=2, column=3, columnspan=2, padx=(20, 20), pady=(20, 0), sticky="nsew")
359+
self.vehicle_parameters = {}
360+
361+
362+
363+
364+
def update_ui_load_transfer_parameters(self,mmpk_type):
365+
''' Here instead update it to take the weights if the load transfer based planner is selected'''
366+
# If planner type is 0, destroy the widgets inside the frame
367+
if mmpk_type == "Static":
368+
# Remove the dictionary
369+
if self.controller.args_dict.get('Planning_Controls', {}).get('Vehicle_Parameters') is not None:
370+
del self.controller.args_dict['Planning_Controls']['Vehicle_Parameters']
371+
for widget in self.planner_load_transfer_frame.winfo_children():
372+
widget.destroy() # Remove all widgets from the frame
373+
return # Exit the function since we don't need to add widgets if planner_type is 0
374+
375+
# If planner type is 1, we create the grid of textboxes and labels
376+
else:
377+
# Clear existing widgets in the frame first to avoid duplication
378+
for widget in self.planner_load_transfer_frame.winfo_children():
379+
widget.destroy()
380+
381+
# Add a label above the textboxes
382+
title_label = ctk.CTkLabel(self.planner_load_transfer_frame,
383+
text="Vehicle Parameters for Load-transfer Planner: Static Weights --> (kg) | Wheelbase/Track-Width --> (meters)")
384+
title_label.grid(row=0, column=0, columnspan=2, pady=10, padx=5, sticky="w")
385+
386+
labels = ['Front-Left', 'Front-Right', 'Rear-Left', 'Rear-Right', 'Wheelbase', 'Track-Width']
387+
row = 1 # Start from row 1 since row 0 has the title label
388+
col = 0 # Start from column 0
389+
390+
# Loop through labels and create corresponding textboxes
391+
for i, label_text in enumerate(labels):
392+
# Create a label for each measurement (weight, wheelbase, track width)
393+
label = ctk.CTkLabel(self.planner_load_transfer_frame, text=label_text)
394+
label.grid(row=row, column=col, padx=2, pady=2, sticky="w")
395+
396+
# Create a corresponding entry field for the measurement
397+
measurement_entry = ctk.CTkEntry(self.planner_load_transfer_frame)
398+
measurement_entry.grid(row=row, column=col + 1, padx=5, pady=5, sticky="w")
399+
400+
# Store the entry widget in the dictionary for later use
401+
self.vehicle_parameters[label_text] = measurement_entry
402+
403+
# Move to next column or row (2 columns per row)
404+
col += 2
405+
if col >= 4: # After filling 2 columns, move to the next row
406+
col = 0
407+
row += 1
408+
409+
# Add a Button to trigger saving into the dictionary
410+
save_button_lt = ctk.CTkButton(master=self.planner_load_transfer_frame, text="Apply",
411+
command=self.save_vehicle_load)
412+
save_button_lt.grid(row=row, column=0, columnspan=2, pady=10) # Ensure the button spans the whole row
352413

353414
''' Helper functions'''
354415
# Rostopic functions
@@ -373,6 +434,7 @@ def save_mpc_costs(self):
373434
self.show_warning_cost("Control Action Penalty")
374435
return
375436

437+
messagebox.showinfo("Success","MPC cost matrix has been saved successfully!")
376438
self.controller.args_dict['Planning_Controls']['Q'] = state_penalty
377439
self.controller.args_dict['Planning_Controls']['R'] = control_penalty
378440

@@ -388,7 +450,7 @@ def save_horizon_values(self):
388450
if not self.validate_input_horizon(planner_horizon):
389451
self.show_warning_horizon("Control Action Penalty")
390452
return
391-
453+
messagebox.showinfo("Success","Controller/Planner horizons have been saved successfully!")
392454
self.controller.args_dict['Planning_Controls']['N'] = model_control_horizon
393455
self.controller.args_dict['Planning_Controls']['N_p'] = planner_horizon
394456

@@ -427,6 +489,36 @@ def save_planner_type(self):
427489
planner_type_map = {0: "Curvature_based", 1: "Load_transfer_based"}
428490
planner_type = self.radio_var_planner_type.get()
429491
self.controller.args_dict['Planning_Controls']['Planner_type'] = planner_type_map[int(planner_type)]
492+
# self.update_ui_load_transfer_parameters(planner_type)
493+
494+
def save_vehicle_load(self):
495+
# Iterate over the key-value pairs in the self.vehicle_parameters dictionary
496+
# Create a new dict
497+
validated_params = {}
498+
for label_text, entry in self.vehicle_parameters.items():
499+
# Get the value entered in the entry field
500+
param_value = entry.get()
501+
try:
502+
# Try to convert the weight value to a float
503+
param_value = float(param_value)
504+
except ValueError:
505+
# If the value can't be converted to a float, show a warning message
506+
messagebox.showwarning("Invalid Input",
507+
f"Invalid weight entered for {label_text}. Please enter a valid number.")
508+
return # Exit the function after showing the warning
509+
510+
# Optionally, check if the value is positive (as vehicle weight should be positive)
511+
if param_value <= 0:
512+
messagebox.showwarning("Invalid Input",
513+
f"Invalid weight entered for {label_text}. Weight should be a positive number.")
514+
return # Exit the function after showing the warning
515+
516+
# If all the validation checks are successful, rewrite the dict with base value
517+
validated_params[label_text] = param_value
518+
519+
# If all entries are valid, you can proceed with saving or further processing the data
520+
messagebox.showinfo("Success", "Vehicle parameters have been saved successfully!")
521+
self.controller.args_dict['Planning_Controls']['Vehicle_Parameters'] = validated_params
430522

431523

432524
'''Validation Functions'''

Update_notes.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
03/12/25
2+
***Motion Planning***
3+
Bug and typo fixes
4+
Added more info messages for successful validation checks
5+
*** Major update:
6+
- Refactored the control+planner horizon and the motion planning selection frames into 1 single function/frame
7+
- Created a new function/frame to consider the vehicle loads for the load transfer based planner called "update_ui_load_transfer_parameters"
8+
- Added checks for ensuring that float values are entered
9+
110
01/21/25
211
***Modeling***
312
Added new functionality to provide curvature limits

0 commit comments

Comments
 (0)