ardupilot-methodic-configurator 2.5.0__py3-none-any.whl → 2.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ardupilot-methodic-configurator might be problematic. Click here for more details.

Files changed (101) hide show
  1. ardupilot_methodic_configurator/__init__.py +1 -1
  2. ardupilot_methodic_configurator/backend_filesystem_program_settings.py +15 -20
  3. ardupilot_methodic_configurator/configuration_manager.py +113 -1
  4. ardupilot_methodic_configurator/data_model_configuration_step.py +40 -3
  5. ardupilot_methodic_configurator/frontend_tkinter_base_window.py +4 -0
  6. ardupilot_methodic_configurator/frontend_tkinter_component_editor_base.py +1 -1
  7. ardupilot_methodic_configurator/frontend_tkinter_motor_test.py +853 -0
  8. ardupilot_methodic_configurator/frontend_tkinter_parameter_editor.py +8 -12
  9. ardupilot_methodic_configurator/frontend_tkinter_parameter_editor_table.py +78 -108
  10. ardupilot_methodic_configurator/frontend_tkinter_usage_popup_window.py +11 -6
  11. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500/07_esc.param +1 -1
  12. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500/42_system_id_roll.param +5 -3
  13. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500/43_system_id_pitch.param +3 -3
  14. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500/44_system_id_yaw.param +1 -1
  15. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500/vehicle.jpg +0 -0
  16. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500/vehicle_components.json +3 -4
  17. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500_V2/05_remote_controller.param +7 -7
  18. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500_V2/06_telemetry.param +2 -0
  19. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500_V2/07_esc.param +6 -6
  20. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500_V2/10_gnss.param +4 -4
  21. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500_V2/13_general_configuration.param +5 -5
  22. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500_V2/15_motor.param +1 -1
  23. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500_V2/16_pid_adjustment.param +10 -10
  24. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500_V2/18_notch_filter_setup.param +3 -3
  25. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500_V2/20_throttle_controller.param +1 -1
  26. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500_V2/22_quick_tune_setup.param +1 -1
  27. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500_V2/26_quick_tune_setup.param +2 -2
  28. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500_V2/30_autotune_roll_setup.param +1 -0
  29. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500_V2/34_autotune_yaw_setup.param +1 -1
  30. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500_V2/37_autotune_yawd_results.param +1 -1
  31. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/Holybro_X500_V2/vehicle.jpg +0 -0
  32. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/00_default.param +1352 -0
  33. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/02_imu_temperature_calibration_setup.param +8 -0
  34. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/03_imu_temperature_calibration_results.param +42 -0
  35. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/04_board_orientation.param +4 -0
  36. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/05_remote_controller.param +13 -0
  37. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/06_telemetry.param +4 -0
  38. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/07_esc.param +43 -0
  39. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/08_batt1.param +15 -0
  40. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/10_gnss.param +11 -0
  41. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/11_initial_atc.param +18 -0
  42. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/12_mp_setup_mandatory_hardware.param +99 -0
  43. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/13_general_configuration.param +17 -0
  44. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/14_logging.param +6 -0
  45. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/15_motor.param +4 -0
  46. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/16_pid_adjustment.param +13 -0
  47. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/17_remote_id.param +4 -0
  48. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/18_notch_filter_setup.param +10 -0
  49. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/19_notch_filter_results.param +7 -0
  50. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/20_throttle_controller.param +5 -0
  51. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/21_ekf_config.param +2 -0
  52. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/22_quick_tune_setup.param +14 -0
  53. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/23_quick_tune_results.param +10 -0
  54. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/24_inflight_magnetometer_fit_setup.param +8 -0
  55. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/24_inflight_magnetometer_fit_setup.pdef.xml +57 -0
  56. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/25_inflight_magnetometer_fit_results.param +15 -0
  57. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/26_quick_tune_setup.param +14 -0
  58. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/27_quick_tune_results.param +10 -0
  59. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/28_evaluate_the_aircraft_tune_ff_disable.param +4 -0
  60. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/29_evaluate_the_aircraft_tune_ff_enable.param +1 -0
  61. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/30_autotune_roll_setup.param +2 -0
  62. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/31_autotune_roll_results.param +5 -0
  63. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/32_autotune_pitch_setup.param +2 -0
  64. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/33_autotune_pitch_results.param +5 -0
  65. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/34_autotune_yaw_setup.param +3 -0
  66. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/35_autotune_yaw_results.param +5 -0
  67. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/36_autotune_yawd_setup.param +3 -0
  68. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/37_autotune_yawd_results.param +5 -0
  69. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/38_autotune_roll_pitch_retune_setup.param +2 -0
  70. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/39_autotune_roll_pitch_retune_results.param +10 -0
  71. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/40_windspeed_estimation.param +5 -0
  72. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/41_barometer_compensation.param +7 -0
  73. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/42_system_id_roll.param +21 -0
  74. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/43_system_id_pitch.param +10 -0
  75. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/44_system_id_yaw.param +10 -0
  76. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/45_system_id_thrust.param +10 -0
  77. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/46_analytical_pid_optimization.param +4 -0
  78. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/47_position_controller.param +13 -0
  79. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/48_guided_operation.param +4 -0
  80. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/49_precision_land.param +27 -0
  81. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/50_optical_flow_setup.param +19 -0
  82. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/51_optical_flow_results.param +3 -0
  83. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/52_use_optical_flow_instead_of_gnss.param +8 -0
  84. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/53_everyday_use.param +7 -0
  85. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/vehicle.jpg +0 -0
  86. ardupilot_methodic_configurator/vehicle_templates/ArduCopter/TarotFY680Hexacopter/vehicle_components.json +188 -0
  87. {ardupilot_methodic_configurator-2.5.0.dist-info → ardupilot_methodic_configurator-2.6.0.dist-info}/METADATA +74 -134
  88. {ardupilot_methodic_configurator-2.5.0.dist-info → ardupilot_methodic_configurator-2.6.0.dist-info}/RECORD +101 -43
  89. {ardupilot_methodic_configurator-2.5.0.dist-info → ardupilot_methodic_configurator-2.6.0.dist-info}/WHEEL +0 -0
  90. {ardupilot_methodic_configurator-2.5.0.dist-info → ardupilot_methodic_configurator-2.6.0.dist-info}/entry_points.txt +0 -0
  91. {ardupilot_methodic_configurator-2.5.0.dist-info → ardupilot_methodic_configurator-2.6.0.dist-info}/licenses/LICENSE.md +0 -0
  92. {ardupilot_methodic_configurator-2.5.0.dist-info → ardupilot_methodic_configurator-2.6.0.dist-info}/licenses/LICENSES/Apache-2.0.txt +0 -0
  93. {ardupilot_methodic_configurator-2.5.0.dist-info → ardupilot_methodic_configurator-2.6.0.dist-info}/licenses/LICENSES/BSD-3-Clause.txt +0 -0
  94. {ardupilot_methodic_configurator-2.5.0.dist-info → ardupilot_methodic_configurator-2.6.0.dist-info}/licenses/LICENSES/GPL-3.0-or-later.txt +0 -0
  95. {ardupilot_methodic_configurator-2.5.0.dist-info → ardupilot_methodic_configurator-2.6.0.dist-info}/licenses/LICENSES/LGPL-3.0-or-later.txt +0 -0
  96. {ardupilot_methodic_configurator-2.5.0.dist-info → ardupilot_methodic_configurator-2.6.0.dist-info}/licenses/LICENSES/MIT-CMU.txt +0 -0
  97. {ardupilot_methodic_configurator-2.5.0.dist-info → ardupilot_methodic_configurator-2.6.0.dist-info}/licenses/LICENSES/MIT.txt +0 -0
  98. {ardupilot_methodic_configurator-2.5.0.dist-info → ardupilot_methodic_configurator-2.6.0.dist-info}/licenses/LICENSES/MPL-2.0.txt +0 -0
  99. {ardupilot_methodic_configurator-2.5.0.dist-info → ardupilot_methodic_configurator-2.6.0.dist-info}/licenses/LICENSES/PSF-2.0.txt +0 -0
  100. {ardupilot_methodic_configurator-2.5.0.dist-info → ardupilot_methodic_configurator-2.6.0.dist-info}/licenses/credits/CREDITS.md +0 -0
  101. {ardupilot_methodic_configurator-2.5.0.dist-info → ardupilot_methodic_configurator-2.6.0.dist-info}/top_level.txt +0 -0
@@ -12,4 +12,4 @@ from ardupilot_methodic_configurator.internationalization import load_translatio
12
12
 
13
13
  _ = load_translation()
14
14
 
15
- __version__ = "2.5.0"
15
+ __version__ = "2.6.0"
@@ -10,7 +10,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
10
10
 
11
11
  # from sys import exit as sys_exit
12
12
  import glob
13
- import sys
13
+ from importlib.resources import files as importlib_files
14
14
  from json import dump as json_dump
15
15
  from json import load as json_load
16
16
  from logging import debug as logging_debug
@@ -18,6 +18,7 @@ from logging import error as logging_error
18
18
  from os import makedirs as os_makedirs
19
19
  from os import path as os_path
20
20
  from os import sep as os_sep
21
+ from pathlib import Path
21
22
  from platform import system as platform_system
22
23
  from re import escape as re_escape
23
24
  from re import match as re_match
@@ -107,13 +108,13 @@ class ProgramSettings:
107
108
 
108
109
  @staticmethod
109
110
  def application_icon_filepath() -> str:
110
- script_dir = os_path.dirname(os_path.abspath(__file__))
111
- return os_path.join(script_dir, "images", "ArduPilot_icon.png")
111
+ package_path = importlib_files("ardupilot_methodic_configurator")
112
+ return str(package_path / "images" / "ArduPilot_icon.png")
112
113
 
113
114
  @staticmethod
114
115
  def application_logo_filepath() -> str:
115
- script_dir = os_path.dirname(os_path.abspath(__file__))
116
- return os_path.join(script_dir, "images", "ArduPilot_logo.png")
116
+ package_path = importlib_files("ardupilot_methodic_configurator")
117
+ return str(package_path / "images" / "ArduPilot_logo.png")
117
118
 
118
119
  @staticmethod
119
120
  def create_new_vehicle_dir(new_vehicle_dir: str) -> str:
@@ -256,15 +257,14 @@ class ProgramSettings:
256
257
 
257
258
  @staticmethod
258
259
  def get_templates_base_dir() -> str:
259
- current_script_dir = os_path.dirname(os_path.abspath(__file__))
260
+ package_path = importlib_files("ardupilot_methodic_configurator")
261
+ logging_debug("current script directory1: %s", package_path)
260
262
  if platform_system() == "Windows":
261
- site_directory = ProgramSettings._site_config_dir()
262
- else:
263
- logging_debug("current script directory: %s", current_script_dir)
264
- site_directory = current_script_dir
263
+ package_path = Path(ProgramSettings._site_config_dir())
264
+ logging_debug("current script directory2: %s", package_path)
265
265
 
266
- logging_debug(_("site_directory: %s"), site_directory)
267
- return os_path.join(site_directory, "vehicle_templates")
266
+ logging_debug(_("site_directory: %s"), package_path)
267
+ return str(package_path / "vehicle_templates")
268
268
 
269
269
  @staticmethod
270
270
  def get_recently_used_dirs() -> tuple[str, str, str]:
@@ -357,20 +357,15 @@ class ProgramSettings:
357
357
  """
358
358
  # See https://github.com/ArduPilot/ardupilot_wiki/pull/6215
359
359
  # Determine the application directory (where images are stored)
360
- if getattr(sys, "frozen", False):
361
- # Running as compiled executable
362
- application_path = os_path.dirname(sys.executable)
363
- else:
364
- # Running as script
365
- application_path = os_path.dirname(os_path.dirname(os_path.abspath(__file__)))
360
+ package_path = importlib_files("ardupilot_methodic_configurator")
366
361
 
367
- images_dir = os_path.join(application_path, "ardupilot_methodic_configurator", "images", "motor_diagrams_png")
362
+ images_dir = package_path / "images" / "motor_diagrams_png"
368
363
 
369
364
  # Generate PNG filename based on frame configuration
370
365
  filename = f"m_{frame_class:02d}_{frame_type:02d}_*.png"
371
366
 
372
367
  # Search for matching PNG file (since exact naming varies)
373
- matching_files = glob.glob(os_path.join(images_dir, filename))
368
+ matching_files = glob.glob(str(images_dir / filename))
374
369
 
375
370
  err_msg = (
376
371
  ""
@@ -22,6 +22,8 @@ from ardupilot_methodic_configurator import _
22
22
  from ardupilot_methodic_configurator.backend_filesystem import LocalFilesystem
23
23
  from ardupilot_methodic_configurator.backend_flightcontroller import FlightController
24
24
  from ardupilot_methodic_configurator.backend_internet import download_file_from_url
25
+ from ardupilot_methodic_configurator.data_model_ardupilot_parameter import ArduPilotParameter
26
+ from ardupilot_methodic_configurator.data_model_configuration_step import ConfigurationStepProcessor
25
27
  from ardupilot_methodic_configurator.data_model_par_dict import Par, ParDict, is_within_tolerance
26
28
  from ardupilot_methodic_configurator.tempcal_imu import IMUfit
27
29
 
@@ -32,10 +34,19 @@ ShowWarningCallback = Callable[[str, str], None] # (title, message) -> None
32
34
  ShowErrorCallback = Callable[[str, str], None] # (title, message) -> None
33
35
  ShowInfoCallback = Callable[[str, str], None] # (title, message) -> None
34
36
 
37
+
38
+ class OperationNotPossibleError(Exception):
39
+ """Raised when an operation cannot be performed due to missing prerequisites or state."""
40
+
41
+
42
+ class InvalidParameterNameError(Exception):
43
+ """Raised when a parameter name is invalid or already exists."""
44
+
45
+
35
46
  # pylint: disable=too-many-lines
36
47
 
37
48
 
38
- class ConfigurationManager:
49
+ class ConfigurationManager: # pylint: disable=too-many-public-methods
39
50
  """
40
51
  Manages configuration state, including flight controller and filesystem access.
41
52
 
@@ -48,6 +59,11 @@ class ConfigurationManager:
48
59
  self.current_file = current_file
49
60
  self.flight_controller = flight_controller
50
61
  self.filesystem = filesystem
62
+ self.config_step_processor = ConfigurationStepProcessor(self.filesystem)
63
+
64
+ # self.parameters is rebuilt on every repopulate(...) call and only contains the ArduPilotParameter
65
+ # objects needed for the current table view.
66
+ self.parameters: dict[str, ArduPilotParameter] = {}
51
67
 
52
68
  @property
53
69
  def connected_vehicle_type(self) -> str:
@@ -77,6 +93,10 @@ class ConfigurationManager:
77
93
  else False
78
94
  )
79
95
 
96
+ @property
97
+ def current_file_parameters(self) -> ParDict:
98
+ return self.filesystem.file_parameters.get(self.current_file, ParDict())
99
+
80
100
  def handle_imu_temperature_calibration_workflow( # pylint: disable=too-many-arguments, too-many-positional-arguments
81
101
  self,
82
102
  selected_file: str,
@@ -1038,3 +1058,95 @@ class ConfigurationManager:
1038
1058
  show_info(_("Parameter files zipped"), msg.format(zip_file_path=zip_file_path))
1039
1059
 
1040
1060
  return should_write_file
1061
+
1062
+ def repopulate_configuration_step_parameters(
1063
+ self,
1064
+ ) -> tuple[bool, list[tuple[str, str]], list[tuple[str, str]]]:
1065
+ """
1066
+ Process the configuration step for the current file and update the self.parameters.
1067
+
1068
+ Returns:
1069
+ tuple: (config_step_edited, ui_errors, ui_infos)
1070
+
1071
+ """
1072
+ self.parameters, config_step_edited, ui_errors, ui_infos = self.config_step_processor.process_configuration_step(
1073
+ self.current_file, self.fc_parameters
1074
+ )
1075
+ return config_step_edited, ui_errors, ui_infos
1076
+
1077
+ def get_different_parameters(self) -> dict[str, ArduPilotParameter]:
1078
+ """
1079
+ Get parameters that are different from FC values or missing from FC.
1080
+
1081
+ Returns:
1082
+ Dictionary of parameters that are different from FC
1083
+
1084
+ """
1085
+ return self.config_step_processor.filter_different_parameters(self.parameters)
1086
+
1087
+ def delete_parameter_from_current_file(self, param_name: str) -> None:
1088
+ """
1089
+ Delete a parameter from the current file parameters.
1090
+
1091
+ Args:
1092
+ param_name: The name of the parameter to delete
1093
+
1094
+ """
1095
+ del self.current_file_parameters[param_name]
1096
+ if param_name in self.parameters:
1097
+ del self.parameters[param_name]
1098
+
1099
+ def get_possible_add_param_names(self) -> list[str]:
1100
+ """Return a sorted list of possible parameter names to add, or raise OperationNotPossibleError if not possible."""
1101
+ param_dict = self.filesystem.doc_dict or self.fc_parameters
1102
+ if not param_dict:
1103
+ raise OperationNotPossibleError(
1104
+ _("No apm.pdef.xml file and no FC connected. Not possible autocomplete parameter names.")
1105
+ )
1106
+ possible_add_param_names = [param_name for param_name in param_dict if param_name not in self.current_file_parameters]
1107
+ possible_add_param_names.sort()
1108
+ return possible_add_param_names
1109
+
1110
+ def add_parameter_to_current_file(self, param_name: str) -> bool:
1111
+ """
1112
+ Add a parameter to the current file.
1113
+
1114
+ Returns True if the parameter was added, False if not.
1115
+
1116
+ Raises InvalidParameterNameError or OperationNotPossibleError if not possible.
1117
+ """
1118
+ param_name = param_name.upper()
1119
+ if not param_name:
1120
+ raise InvalidParameterNameError(_("Parameter name can not be empty."))
1121
+
1122
+ if param_name in self.current_file_parameters:
1123
+ raise InvalidParameterNameError(_("Parameter already exists, edit it instead"))
1124
+
1125
+ fc_parameters = self.fc_parameters
1126
+ if fc_parameters:
1127
+ if param_name in fc_parameters:
1128
+ self.current_file_parameters[param_name] = Par(fc_parameters[param_name], "")
1129
+ self.parameters[param_name] = self.config_step_processor.create_ardupilot_parameter(
1130
+ param_name, self.current_file_parameters[param_name], self.current_file, fc_parameters
1131
+ )
1132
+ return True
1133
+ raise InvalidParameterNameError(_("Parameter name not found in the flight controller."))
1134
+
1135
+ if self.filesystem.doc_dict:
1136
+ if param_name in self.filesystem.doc_dict:
1137
+ self.current_file_parameters[param_name] = Par(
1138
+ self.filesystem.param_default_dict.get(param_name, Par(0, "")).value, ""
1139
+ )
1140
+ self.parameters[param_name] = self.config_step_processor.create_ardupilot_parameter(
1141
+ param_name, self.current_file_parameters[param_name], self.current_file, fc_parameters
1142
+ )
1143
+ return True
1144
+ raise InvalidParameterNameError(
1145
+ _("'{param_name}' not found in the apm.pdef.xml file.").format(param_name=param_name)
1146
+ )
1147
+
1148
+ if not fc_parameters and not self.filesystem.doc_dict:
1149
+ raise OperationNotPossibleError(
1150
+ _("Can not add parameter when no FC is connected and no apm.pdef.xml file exists.")
1151
+ )
1152
+ return False
@@ -17,7 +17,7 @@ from typing import Any, Optional
17
17
  from ardupilot_methodic_configurator import _
18
18
  from ardupilot_methodic_configurator.backend_filesystem import LocalFilesystem
19
19
  from ardupilot_methodic_configurator.data_model_ardupilot_parameter import ArduPilotParameter
20
- from ardupilot_methodic_configurator.data_model_par_dict import ParDict
20
+ from ardupilot_methodic_configurator.data_model_par_dict import Par, ParDict
21
21
 
22
22
 
23
23
  class ConfigurationStepProcessor:
@@ -38,11 +38,14 @@ class ConfigurationStepProcessor:
38
38
  """
39
39
  self.local_filesystem = local_filesystem
40
40
 
41
+ # A dictionary that maps variable names to their values
42
+ # These variables are used by the forced_parameters and derived_parameters in configuration_steps_*.json files
43
+ self.variables = self.local_filesystem.get_eval_variables()
44
+
41
45
  def process_configuration_step(
42
46
  self,
43
47
  selected_file: str,
44
48
  fc_parameters: dict[str, float],
45
- variables: dict,
46
49
  ) -> tuple[dict[str, ArduPilotParameter], bool, list[tuple[str, str]], list[tuple[str, str]]]:
47
50
  """
48
51
  Process a configuration step including parameter computation and domain model creation.
@@ -50,7 +53,6 @@ class ConfigurationStepProcessor:
50
53
  Args:
51
54
  selected_file: The name of the selected parameter file
52
55
  fc_parameters: Dictionary of flight controller parameters
53
- variables: Variables dictionary for evaluation
54
56
 
55
57
  Returns:
56
58
  Tuple containing:
@@ -66,6 +68,7 @@ class ConfigurationStepProcessor:
66
68
 
67
69
  # Process configuration step operations if configuration steps exist
68
70
  if self.local_filesystem.configuration_steps and selected_file in self.local_filesystem.configuration_steps:
71
+ variables = self.variables
69
72
  variables["fc_parameters"] = fc_parameters
70
73
 
71
74
  # Compute derived parameters
@@ -261,3 +264,37 @@ class ConfigurationStepProcessor:
261
264
  renamed_pairs.append((old_name, new_name))
262
265
 
263
266
  return duplicates, renamed_pairs
267
+
268
+ def create_ardupilot_parameter(
269
+ self,
270
+ param_name: str,
271
+ param: Par,
272
+ selected_file: str,
273
+ fc_parameters: dict[str, float],
274
+ ) -> ArduPilotParameter:
275
+ """
276
+ Create an ArduPilotParameter domain model object.
277
+
278
+ Args:
279
+ param_name: The name of the parameter
280
+ param: The parameter object from the file
281
+ selected_file: The name of the selected parameter file
282
+ fc_parameters: Dictionary of flight controller parameters
283
+
284
+ Returns:
285
+ ArduPilotParameter: The created domain model parameter
286
+
287
+ """
288
+ # Get parameter metadata and default values
289
+ metadata = self.local_filesystem.doc_dict.get(param_name, {})
290
+ default_par = self.local_filesystem.param_default_dict.get(param_name, None)
291
+
292
+ # Check if parameter is forced or derived
293
+ forced_par = self.local_filesystem.forced_parameters.get(selected_file, ParDict()).get(param_name, None)
294
+ derived_par = self.local_filesystem.derived_parameters.get(selected_file, ParDict()).get(param_name, None)
295
+
296
+ # Get FC value if available
297
+ fc_value = fc_parameters.get(param_name)
298
+
299
+ # Create domain model parameter
300
+ return ArduPilotParameter(param_name, param, metadata, default_par, fc_value, forced_par, derived_par)
@@ -281,9 +281,13 @@ class BaseWindow:
281
281
  parent_height = parent.winfo_height()
282
282
  window_width = window.winfo_width()
283
283
  window_height = window.winfo_height()
284
+ # logging_error(_("Parent position: %d,%d"), parent.winfo_x(), parent.winfo_y())
285
+ # logging_error(_("Parent size: %dx%d"), parent_width, parent_height)
286
+ # logging_error(_("Window size: %dx%d"), window_width, window_height)
284
287
  x = parent.winfo_x() + (parent_width // 2) - (window_width // 2)
285
288
  y = parent.winfo_y() + (parent_height // 2) - (window_height // 2)
286
289
  window.geometry(f"+{x}+{y}")
290
+ window.update()
287
291
 
288
292
  def put_image_in_label( # pylint: disable=too-many-locals
289
293
  self,
@@ -289,7 +289,7 @@ class ComponentEditorWindowBase(BaseWindow): # pylint: disable=too-many-instanc
289
289
  """Check if usage instructions should be displayed."""
290
290
  if UsagePopupWindow.should_display("component_editor"):
291
291
  # Cast to Tk since we know root is a Tk instance in this context
292
- self.root.after(10, lambda: self._display_component_editor_usage_instructions(cast("tk.Tk", self.root)))
292
+ self.root.after(1, lambda: self._display_component_editor_usage_instructions(cast("tk.Tk", self.root)))
293
293
 
294
294
  def _display_component_editor_usage_instructions(self, parent: tk.Tk) -> None:
295
295
  """Display usage instructions for the component editor."""