Skip to content

Commit

Permalink
FEATURE: Use FC parameter values instead of template files values
Browse files Browse the repository at this point in the history
  • Loading branch information
amilcarlucas committed May 27, 2024
1 parent 5b84588 commit 10582a9
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 13 deletions.
30 changes: 27 additions & 3 deletions MethodicConfigurator/ardupilot_methodic_configurator.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
from logging import warning as logging_warning
from logging import error as logging_error
from sys import exit as sys_exit
import tkinter as tk

Check failure on line 19 in MethodicConfigurator/ardupilot_methodic_configurator.py

View workflow job for this annotation

GitHub Actions / build (3.10)

Ruff (F401)

MethodicConfigurator/ardupilot_methodic_configurator.py:19:19: F401 `tkinter` imported but unused

Check failure on line 19 in MethodicConfigurator/ardupilot_methodic_configurator.py

View workflow job for this annotation

GitHub Actions / build (3.10)

Ruff (F401)

MethodicConfigurator/ardupilot_methodic_configurator.py:19:19: F401 `tkinter` imported but unused

from backend_filesystem import LocalFilesystem
from backend_flightcontroller import FlightController

from frontend_tkinter_base import ProgressWindow

from frontend_tkinter_connection_selection import ConnectionSelectionWindow

from frontend_tkinter_directory_selection import VehicleDirectorySelectionWindow
Expand Down Expand Up @@ -90,17 +93,38 @@ def main():
# Get the list of intermediate parameter files files that will be processed sequentially
files = list(local_filesystem.file_parameters.keys())

vehicle_dir_window = None
if not files:
vehicle_dir_window = VehicleDirectorySelectionWindow(local_filesystem)
vehicle_dir_window = VehicleDirectorySelectionWindow(local_filesystem, flight_controller.master is not None)
vehicle_dir_window.root.mainloop()

start_file = local_filesystem.get_start_file(args.n)

component_editor_window = ComponentEditorWindow(VERSION, local_filesystem)
component_editor_window.set_vehicle_type_and_version(vehicle_type, flight_controller.version)
if vehicle_dir_window and \
vehicle_dir_window.created_new_vehicle_from_template and \
flight_controller.master is not None:
param_download_progress_window = ProgressWindow(component_editor_window.root, "Downloading FC parameters",
"Downloaded {} of {} parameters")
# Download all parameters from the flight controller
flight_controller.fc_parameters = flight_controller.download_params(
param_download_progress_window.update_progress_bar)
param_download_progress_window.destroy() # for the case that '--device test' and there is no real FC connected
# copy vehicle parameters to component editor values
component_editor_window.set_values_from_fc_parameters(flight_controller.fc_parameters, local_filesystem.doc_dict)
if not args.skip_component_editor:
component_editor_window = ComponentEditorWindow(VERSION, local_filesystem)
component_editor_window.set_vehicle_type_and_version(vehicle_type, flight_controller.version)
component_editor_window.root.mainloop()

if vehicle_dir_window and \
vehicle_dir_window.created_new_vehicle_from_template and \
vehicle_dir_window.use_fc_params.get():
error_message = local_filesystem.copy_fc_params_values_to_created_vehicle_from_template(flight_controller.fc_parameters)
if error_message:
logging_error(error_message)
#messagebox.showerror("Error in derived parameters", error_msg)
sys_exit(1)

# Call the GUI function with the starting intermediate parameter file
ParameterEditorWindow(start_file, flight_controller, local_filesystem, VERSION)

Expand Down
26 changes: 26 additions & 0 deletions MethodicConfigurator/backend_filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,32 @@ def get_start_file(self, explicit_index: int):
start_file_index = len(files) - 1
return files[start_file_index]

def get_eval_variables(self):
variables = {}
if hasattr(self, 'vehicle_components') and self.vehicle_components and \
'Components' in self.vehicle_components:
variables['vehicle_components'] = self.vehicle_components['Components']
if hasattr(self, 'doc_dict') and self.doc_dict:
variables['doc_dict'] = self.doc_dict
return variables

def copy_fc_params_values_to_created_vehicle_from_template(self, fc_parameters: Dict[str, 'Par']):
eval_variables = self.get_eval_variables()
for param_filename, param_dict in self.file_parameters.items():
for param_name, param in param_dict.items():
if param_name in fc_parameters:
param.value = fc_parameters[param_name]
if self.configuration_steps and param_filename in self.configuration_steps:
step_dict = self.configuration_steps[param_filename]
error_msg = self.compute_parameters(param_filename, step_dict, 'forced', eval_variables)
if error_msg:
return error_msg
error_msg = self.compute_parameters(param_filename, step_dict, 'derived', eval_variables)
if error_msg:
return error_msg
Par.export_to_param(Par.format_params(param_dict), os_path.join(self.vehicle_dir, param_filename))
return ''

@staticmethod
def supported_vehicles():
return ['AP_Periph', 'AntennaTracker', 'ArduCopter', 'ArduPlane',
Expand Down
33 changes: 33 additions & 0 deletions MethodicConfigurator/frontend_tkinter_component_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,39 @@ def set_vehicle_type_and_version(self, vehicle_type: str, version: str):
entry.insert(0, version)
entry.config(state="disabled")

@staticmethod
def reverse_key_search(doc: dict, param_name: str, values: list) -> list:
return [key for key, value in doc[param_name]["values"].items() if value in values]

def set_values_from_fc_parameters(self, fc_parameters: dict, doc: dict):
serial_ports = ["SERIAL1", "SERIAL2", "SERIAL3", "SERIAL4", "SERIAL5", "SERIAL6", "SERIAL7", "SERIAL8"]
can_ports = ["CAN1", "CAN2"]

Check failure on line 101 in MethodicConfigurator/frontend_tkinter_component_editor.py

View workflow job for this annotation

GitHub Actions / build (3.10)

Ruff (F841)

MethodicConfigurator/frontend_tkinter_component_editor.py:101:9: F841 Local variable `can_ports` is assigned to but never used

Check failure on line 101 in MethodicConfigurator/frontend_tkinter_component_editor.py

View workflow job for this annotation

GitHub Actions / build (3.10)

Ruff (F841)

MethodicConfigurator/frontend_tkinter_component_editor.py:101:9: F841 Local variable `can_ports` is assigned to but never used
i2c_ports = ["I2C1", "I2C2", "I2C3", "I2C4"]

Check failure on line 102 in MethodicConfigurator/frontend_tkinter_component_editor.py

View workflow job for this annotation

GitHub Actions / build (3.10)

Ruff (F841)

MethodicConfigurator/frontend_tkinter_component_editor.py:102:9: F841 Local variable `i2c_ports` is assigned to but never used

Check failure on line 102 in MethodicConfigurator/frontend_tkinter_component_editor.py

View workflow job for this annotation

GitHub Actions / build (3.10)

Ruff (F841)

MethodicConfigurator/frontend_tkinter_component_editor.py:102:9: F841 Local variable `i2c_ports` is assigned to but never used

rc_receiver_protocols = self.reverse_key_search(doc, "SERIAL1_PROTOCOL", ["RC Input"])
telemetry_protocols = self.reverse_key_search(doc, "SERIAL1_PROTOCOL", ["MAVLink1", "MAVLink2", "MAVLink High Latency"])
gnss_protocols = self.reverse_key_search(doc, "SERIAL1_PROTOCOL", ["GPS"])
esc_protocols = self.reverse_key_search(doc, "SERIAL1_PROTOCOL", ["ESC Telemetry", "FETtecOneWire", "CoDevESC"])
for serial in serial_ports:
if serial + "_PROTOCOL" in fc_parameters:
if fc_parameters[serial + "_PROTOCOL"] in rc_receiver_protocols:
self.data['Components']['RC Receiver']['FC Connection']['Type'] = serial
#self.data['Components']['RC Receiver']['FC Connection']['Protocol'] = doc['RC_PROTOCOLS']['values'][fc_parameters['RC_PROTOCOLS']]
elif fc_parameters[serial + "_PROTOCOL"] in telemetry_protocols:
self.data['Components']['Telemetry']['FC Connection']['Type'] = serial
self.data['Components']['Telemetry']['FC Connection']['Protocol'] = doc[serial + "_PROTOCOL"]['values'][str(fc_parameters[serial + "_PROTOCOL"]).rstrip('0').rstrip('.')]
elif fc_parameters[serial + "_PROTOCOL"] in gnss_protocols:
self.data['Components']['GNSS Receiver']['FC Connection']['Type'] = serial
self.data['Components']['GNSS Receiver']['FC Connection']['Protocol'] = doc['GPS_TYPE']['values'][str(fc_parameters['GPS_TYPE']).rstrip('0').rstrip('.')]
elif fc_parameters[serial + "_PROTOCOL"] in esc_protocols:
self.data['Components']['ESC']['FC Connection']['Type'] = serial
self.data['Components']['ESC']['FC Connection']['Protocol'] = doc['MOT_PWM_TYPE']['values'][str(fc_parameters['MOT_PWM_TYPE']).rstrip('0').rstrip('.')]
if "BATT_MONITOR" in fc_parameters:
analog = [key for key, value in doc["BATT_MONITOR"]["values"].items() if value in ['Analog Voltage Only', 'Analog Voltage and Current']]
if fc_parameters["BATT_MONITOR"] in analog:
self.data['Components']['Battery Monitor']['FC Connection']['Type'] = "Analog"
self.data['Components']['Battery Monitor']['FC Connection']['Protocol'] = doc['BATT_MONITOR']['values'][str(fc_parameters["BATT_MONITOR"]).rstrip('0').rstrip('.')]

def add_entry_or_combobox(self, value, entry_frame, path):
serial_ports = ["SERIAL1", "SERIAL2", "SERIAL3", "SERIAL4", "SERIAL5", "SERIAL6", "SERIAL7", "SERIAL8"]
can_ports = ["CAN1", "CAN2"]
Expand Down
25 changes: 21 additions & 4 deletions MethodicConfigurator/frontend_tkinter_directory_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
from tkinter import Checkbutton

from common_arguments import add_common_arguments_and_parse

Expand Down Expand Up @@ -182,11 +183,13 @@ class VehicleDirectorySelectionWindow(BaseWindow):
configuration directory based on an existing template or using an existing
vehicle configuration directory.
"""
def __init__(self, local_filesystem: LocalFilesystem):
def __init__(self, local_filesystem: LocalFilesystem, fc_connected: bool = False):
super().__init__()
self.local_filesystem = local_filesystem
self.root.title("Select Vehicle directory")
self.root.geometry("800x535") # Set the window size
self.root.geometry("800x575") # Set the window size
self.use_fc_params = tk.BooleanVar(value=False)
self.created_new_vehicle_from_template = False

# Explain why we are here
if local_filesystem.vehicle_dir == LocalFilesystem.getcwd():
Expand All @@ -199,7 +202,8 @@ def __init__(self, local_filesystem: LocalFilesystem):
template_dir, new_base_dir, vehicle_dir = LocalFilesystem.get_recently_used_dirs()
self.create_option1_widgets(template_dir,
new_base_dir,
"MyVehicleName")
"MyVehicleName",
fc_connected)
self.create_option2_widgets(vehicle_dir)
self.create_option3_widgets(vehicle_dir)

Expand All @@ -209,7 +213,8 @@ def __init__(self, local_filesystem: LocalFilesystem):
def close_and_quit(self):
sys_exit(0)

def create_option1_widgets(self, initial_template_dir: str, initial_base_dir: str, initial_new_dir: str):
def create_option1_widgets(self, initial_template_dir: str, initial_base_dir: str, initial_new_dir: str,
fc_connected: bool):
# Option 1 - Create a new vehicle configuration directory based on an existing template
option1_label_frame = tk.LabelFrame(self.root, text="Create a new vehicle configuration directory")
option1_label_frame.pack(expand=True, fill=tk.X, padx=6, pady=5)
Expand All @@ -223,6 +228,17 @@ def create_option1_widgets(self, initial_template_dir: str, initial_base_dir: st
template_dir_edit_tooltip,
template_dir_btn_tooltip)
self.template_dir.container_frame.pack(expand=False, fill=tk.X, padx=3, pady=5, anchor=tk.NW)

use_fc_params_checkbox = Checkbutton(option1_label_frame, variable=self.use_fc_params,
text="Use parameter values from connected FC, not from template files")
use_fc_params_checkbox.pack(anchor=tk.NW)
show_tooltip(use_fc_params_checkbox, "Use the parameter values from the connected flight controller instead\n" \
"of the template files when creating a new vehicle directory from a template.\n" \
"This option is only available when a flight controller is connected")
if not fc_connected:
self.use_fc_params.set(False)
use_fc_params_checkbox.config(state=tk.DISABLED)

new_base_dir_edit_tooltip = "Existing directory where the new vehicle directory will be created"
new_base_dir_btn_tooltip = "Select the existing directory where the new vehicle directory will be created"
self.new_base_dir = DirectorySelectionWidgets(self, option1_label_frame, initial_base_dir,
Expand Down Expand Up @@ -310,6 +326,7 @@ def create_new_vehicle_from_template(self):
" template vehicle directory.\n" \
"Please select a vehicle directory containing valid ArduPilot intermediate parameter files."
show_error_message("No Parameter Files Found", error_message)
self.created_new_vehicle_from_template = True

def open_last_vehicle_directory(self, last_vehicle_dir: str):
# Attempt to open the last opened vehicle directory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,7 @@ def __init__(self, root, local_filesystem, parameter_editor):

# Prepare a dictionary that maps variable names to their values
# These variables are used by the forced_parameters and derived_parameters in *_configuration_steps.json files
self.variables = {}
if hasattr(self.local_filesystem, 'vehicle_components') and self.local_filesystem.vehicle_components and \
'Components' in self.local_filesystem.vehicle_components:
self.variables['vehicle_components'] = self.local_filesystem.vehicle_components['Components']
if hasattr(self.local_filesystem, 'doc_dict') and self.local_filesystem.doc_dict:
self.variables['doc_dict'] = self.local_filesystem.doc_dict
self.variables = local_filesystem.get_eval_variables()

self.compute_forced_and_derived_parameters()

Expand Down

0 comments on commit 10582a9

Please sign in to comment.