@@ -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'''
0 commit comments