diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index eaa7097..5c9eb1c 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -70,6 +70,8 @@ Navigate into the location where you cloned *Parasect* and install the package w .. code:: console $ poetry install + $ poetry self add poetry-plugin-shell + $ poetry self add poetry-plugin-export You can now run an interactive Poetry shell, giving you access to the virtual environment. diff --git a/poetry.lock b/poetry.lock index 4bc2bf0..77ffe9b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand. [[package]] name = "alabaster" @@ -1310,6 +1310,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -1944,4 +1945,4 @@ tests-strict = ["pytest (==4.6.0) ; python_version < \"3.10.0\" and python_versi [metadata] lock-version = "2.1" python-versions = "^3.10" -content-hash = "69b4d25da33efd1305b23c76f5e452c2dd16c5a4bbf240f19bb7d89b722d60a3" +content-hash = "7bf1d85756f4dc5178ad8ca83aa6afb4e09c5f7cf69b1d767b7d2384e6118d85" diff --git a/pyproject.toml b/pyproject.toml index 192b35d..1f2037e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "parasect" -version = "1.2.0" +version = "1.2.2-dev" description = "Utility for manipulating parameter sets for autopilots." authors = ["George Zogopoulos "] license = "MIT" diff --git a/src/parasect/_helpers.py b/src/parasect/_helpers.py index b04ca45..602bff1 100644 --- a/src/parasect/_helpers.py +++ b/src/parasect/_helpers.py @@ -198,6 +198,8 @@ class Formats(Enum): """Ardupilot-compatible file.""" apj = "apj" """File compatible with Ardupilot's apj tool.""" + mp = "mp" + """Ardupilot Mission Planner comma separated file with comments.""" ReservedOptions = Literal[ @@ -821,20 +823,6 @@ def build_param_from_qgc(row: list[str]) -> Parameter: return param -def build_param_from_ulog_params(row: list[str]) -> Parameter: - """Build a Parameter from an ulog_params printout entry.""" - param_name = row[0] - param_value: int | float - try: - param_value = int(row[1]) - except ValueError: - param_value = float(row[1]) - - param = Parameter(param_name, param_value) - - return param - - def build_param_from_mavproxy(item: Sequence) -> Parameter: """Convert a mavproxy parameter line to a parameter. @@ -847,7 +835,10 @@ def build_param_from_mavproxy(item: Sequence) -> Parameter: value = int(item[1]) except ValueError: value = float(item[1]) - reasoning = item[2] + if len(item) < 3: + reasoning = None + else: + reasoning = item[2] param = Parameter(name, value) param.reasoning = reasoning @@ -951,45 +942,12 @@ def read_params_qgc(filepath: Path) -> ParameterList: raise (SyntaxError("Could not extract any parameter from file.")) return param_list + except UnicodeDecodeError as e: + raise SyntaxError(f"File encoding error - not a valid QGC parameter file: {e}") from e except SyntaxError as e: raise SyntaxError(f"File is not of QGC format:\n{e}") from e -@parser -def read_params_ulog_param(filepath: Path) -> ParameterList: - """Read and parse the outputs of the ulog_params program.""" - param_list = ParameterList() - - try: - with open(filepath) as csvfile: - param_reader = csv.reader(csvfile, delimiter=",") - for param_row in param_reader: # pragma: no branch - if param_row[0][0] == "#": # Skip comment lines - continue - # Check if line has exactly two elements - if len(param_row) != 2: - raise SyntaxError( - f"Invalid number of elements for ulog param decoder: {len(param_row)}" - ) - # Check if first element is a string - try: - float(param_row[0]) - raise SyntaxError( - "First row element must be a parameter name string" - ) - except ValueError: - pass - param = build_param_from_ulog_params(param_row) - param_list.add_param(param) - - if len(param_list.params) == 0: - raise (SyntaxError("Could not extract any parameter from file.")) - - return param_list - except SyntaxError as e: - raise SyntaxError(f"File is not of ulog format:\n{e}") from e - - def split_mavproxy_row(row: str) -> Sequence: """Split a line, assuming it is mavproxy syntax.""" params = row.split() @@ -1015,13 +973,41 @@ def split_mavproxy_row(row: str) -> Sequence: return params +def split_missionplanner_row(row: str) -> Sequence: + """Split a line, assuming it is MissionPlanner or ULOG (as its subset) syntax.""" + params = row.split(",", 1) + # Check if there's at least one comma (should have 2 parts) + if len(params) < 2: + raise SyntaxError("MP: Line must contain at least one comma separator.") + + # Check if first element is a string + try: + float(params[0]) + raise SyntaxError("MP: First row element must be a parameter name string.") + except ValueError: + pass + + value_reasoning = params[1].split("#", 1) + params[1] = value_reasoning[0].strip() + try: + float(params[1]) + except ValueError as e: + raise SyntaxError("MP: First row element must be a parameter name string.") from e + if len(value_reasoning) <= 1: + params.append("") + else: + params.append(value_reasoning[1].strip()) + + return params + + @parser def read_params_mavproxy(filepath: Path) -> ParameterList: """Read and parse the outputs of mavproxy.""" param_list = ParameterList() try: - with open(filepath) as f: + with open(filepath, encoding='utf-8') as f: for line in f: # pragma: no branch if line[0] == "#": # Skip comment lines continue @@ -1037,6 +1023,31 @@ def read_params_mavproxy(filepath: Path) -> ParameterList: raise SyntaxError(f"File is not of mavproxy format:\n{e}") from e +@parser +def read_params_missionplanner(filepath: Path) -> ParameterList: + """Read and parse the outputs of MissionPlanner or ULOG (as its subset).""" + param_list = ParameterList() + + try: + with open(filepath, encoding='utf-8') as f: + for line in f: # pragma: no branch + if line[0] == "#": # Skip comment lines + continue + # skip empty lines + if line.strip() == "": + continue + params = split_missionplanner_row(line) + param = build_param_from_mavproxy(params) + param_list.add_param(param) + + if len(param_list.params) == 0: + raise (SyntaxError("Could not extract any parameter from file.")) + + return param_list + except SyntaxError as e: + raise SyntaxError(f"File is not of MissionPlanner format:\n{e}") from e + + def read_params(filepath: Path) -> ParameterList: """Universal parameter reader.""" get_logger().debug(f"Attempting to read file {filepath}") diff --git a/src/parasect/build_lib.py b/src/parasect/build_lib.py index d910131..d9a0c74 100755 --- a/src/parasect/build_lib.py +++ b/src/parasect/build_lib.py @@ -642,33 +642,45 @@ def export_to_csv(self) -> Generator[str, None, None]: yield from self.retrieve_header_footer("footer", Formats.csv) def export_to_apm( - self, include_readonly: bool = False + self, include_readonly: bool = False, csv: bool = False, comments: bool = False ) -> Generator[str, None, None]: """Export as apm parameter file. INPUTS: include_readonly: flag to enable including @READONLY on a parameter. Necessary for apj tools, unsuitable for loading via a GCS. + csv: flag to use comma-separated format instead of tab-separated. + comments: flag to add parameter descriptions as comments after #. """ # Read header yield from self.retrieve_header_footer("header", Formats.apm) indentation = "" + separator = "," if csv else "\t" param_hashes = sorted(self.param_list.keys()) - for param_name in param_hashes: - param_name = self.param_list[param_name].name - param_value = self.param_list[param_name].get_pretty_value() - is_readonly = self.param_list[param_name].readonly + for param_hash in param_hashes: + param = self.param_list[param_hash] + param_name = param.name + param_value = param.get_pretty_value() + is_readonly = param.readonly + + # Build the parameter line + line = f"{indentation}{param_name}{separator}{param_value}" + + # Add readonly marker if needed if include_readonly and is_readonly: - readonly_string = "\t@READONLY" - else: - readonly_string = "" - - yield f"{indentation}{param_name}\t{param_value}{readonly_string}\n" - - # Read footer - yield from self.retrieve_header_footer("footer", Formats.apm) + readonly_string = f"{separator}@READONLY" if csv else "\t@READONLY" + line += readonly_string + + # Add comment if requested and description is available + if comments and hasattr(param, 'reasoning') and param.reasoning: + line += f" # {param.reasoning}" + + yield line + "\n" + + # Read footer + yield from self.retrieve_header_footer("footer", Formats.apm) def apply_additions_px4(self) -> None: # Add the AUTOSTART value for each configuration @@ -694,6 +706,8 @@ def export(self, format: Formats) -> Iterable[str]: return self.export_to_apm(include_readonly=False) elif format == Formats.apj: return self.export_to_apm(include_readonly=True) + elif format == Formats.mp: + return self.export_to_apm(include_readonly=False, csv=True, comments=True) else: raise ValueError(f"Output format {format} not supported.") @@ -734,6 +748,8 @@ def build_filename(format: Formats, meal: Meal) -> str: filename += ".hil" return filename elif format in (Formats.apm, Formats.apj): + return f"{meal.name}.parm" + elif format == Formats.mp: return f"{meal.name}.param" else: raise ValueError(f"Unsupported format {format}") diff --git a/tests/assets/ardupilot/mission_planner.param b/tests/assets/ardupilot/mission_planner.param new file mode 100644 index 0000000..9701ec8 --- /dev/null +++ b/tests/assets/ardupilot/mission_planner.param @@ -0,0 +1,19 @@ +#ACRO_YAW_RATE,90 + +AHRS_ORIENTATION,25 # realflight + + +### Variant 1 - GPS module + Spooffing +AHRS_GPS_USE,1 +GPS1_TYPE,1 + + +### Variant 2 - LUA Script +#SCR_ENABLE,1 +AHRS_ORIG_LAT,37.090662 +#AHRS_ORIG_LON,-3.0745569 +#AHRS_ORIG_ALT,2736 + + +AHRS_OPTIONS,3 # відключить DCM fallback in VTOL and FW +#AHRS_OPTIONS,7 # don't disable AIRSPEED using EKF біт3 (В СИМУЛЯТОРІ результати гірше - літає боком) diff --git a/tests/assets/ardupilot/sitl_plane_defaults.param b/tests/assets/ardupilot/sitl_plane_defaults.param new file mode 100644 index 0000000..e283caf --- /dev/null +++ b/tests/assets/ardupilot/sitl_plane_defaults.param @@ -0,0 +1,1568 @@ +ACRO_LOCKING,0 +ACRO_PITCH_RATE,180 +ACRO_ROLL_RATE,180 +ACRO_YAW_RATE,0 +ADSB_TYPE,0 +AFS_ENABLE,0 +AHRS_COMP_BETA,0.1 +AHRS_EKF_TYPE,3 +AHRS_GPS_GAIN,1 +AHRS_GPS_MINSATS,6 +AHRS_GPS_USE,1 +AHRS_OPTIONS,0 +AHRS_ORIENTATION,0 +AHRS_RP_P,0.2 +AHRS_TRIM_X,0 +AHRS_TRIM_Y,0 +AHRS_TRIM_Z,0 +AHRS_WIND_MAX,0 +AHRS_YAW_P,0.2 +AIRSPEED_CRUISE,12 +AIRSPEED_MAX,22 +AIRSPEED_MIN,9 +AIRSPEED_STALL,0 +ALT_OFFSET,0 +ARMING_ACCTHRESH,0.75 +ARMING_CHECK,1 +ARMING_CRSDP_IGN,0 +ARMING_MAGTHRESH,100 +ARMING_MIS_ITEMS,0 +ARMING_OPTIONS,0 +ARMING_REQUIRE,1 +ARMING_RUDDER,1 +ARSPD_AUTOCAL,0 +ARSPD_BUS,1 +ARSPD_DEVID,0 +ARSPD_OFF_PCNT,0 +ARSPD_OFFSET,0 +ARSPD_OPTIONS,11 +ARSPD_PIN,4 +ARSPD_PRIMARY,0 +ARSPD_PSI_RANGE,1 +ARSPD_RATIO,2 +ARSPD_SKIP_CAL,0 +ARSPD_TUBE_ORDR,2 +ARSPD_TYPE,1 +ARSPD_USE,0 +ARSPD_WIND_GATE,5 +ARSPD_WIND_MAX,0 +ARSPD_WIND_WARN,0 +ARSPD2_TYPE,0 +AUTOTUNE_AXES,7 +AUTOTUNE_LEVEL,6 +AUTOTUNE_OPTIONS,0 +AVD_ENABLE,0 +BARO_ALT_OFFSET,0 +BARO_ALTERR_MAX,2000 +BARO_EXT_BUS,-1 +BARO_FIELD_ELV,0 +BARO_FLTR_RNG,0 +BARO_GND_TEMP,0 +BARO_OPTIONS,0 +BARO_PRIMARY,0 +BARO_PROBE_EXT,0 +BARO1_DEVID,0 +BARO1_GND_PRESS,0 +BARO1_WCF_ENABLE,0 +BARO2_DEVID,0 +BARO2_GND_PRESS,0 +BARO2_WCF_ENABLE,0 +BARO3_DEVID,0 +BARO3_GND_PRESS,0 +BARO3_WCF_ENABLE,0 +BATT_ARM_MAH,0 +BATT_ARM_VOLT,0 +BATT_CAPACITY,3300 +BATT_CRT_MAH,0 +BATT_CRT_VOLT,0 +BATT_ESC_MASK,0 +BATT_FS_CRT_ACT,0 +BATT_FS_LOW_ACT,0 +BATT_FS_VOLTSRC,0 +BATT_LOW_MAH,0 +BATT_LOW_TIMER,10 +BATT_LOW_VOLT,0 +BATT_MONITOR,9 +BATT_OPTIONS,0 +BATT_SERIAL_NUM,-1 +BATT_WATT_MAX,0 +BATT2_MONITOR,0 +BATT3_MONITOR,0 +BATT4_MONITOR,0 +BATT5_MONITOR,0 +BATT6_MONITOR,0 +BATT7_MONITOR,0 +BATT8_MONITOR,0 +BATT9_MONITOR,0 +BRD_ALT_CONFIG,0 +BRD_BOOT_DELAY,0 +BRD_OPTIONS,1 +BRD_RTC_TYPES,1 +BRD_RTC_TZ_MIN,0 +BRD_SAFETY_DEFLT,0 +BRD_SAFETY_MASK,0 +BRD_SAFETYOPTION,3 +BRD_SD_FENCE,0 +BRD_SD_MISSION,0 +BRD_SD_SLOWDOWN,0 +BRD_SER1_RTSCTS,2 +BRD_SERIAL_NUM,0 +BTN_ENABLE,0 +CAM_AUTO_ONLY,0 +CAM_MAX_ROLL,0 +CAM_RC_TYPE,0 +CAM1_TYPE,0 +CAM2_TYPE,0 +CAN_D1_PROTOCOL,1 +CAN_D1_PROTOCOL2,0 +CAN_D1_UC_ESC_BM,0 +CAN_D1_UC_ESC_OF,0 +CAN_D1_UC_ESC_RV,0 +CAN_D1_UC_NODE,10 +CAN_D1_UC_NTF_RT,20 +CAN_D1_UC_OPTION,0 +CAN_D1_UC_POOL,16384 +CAN_D1_UC_RLY_RT,0 +CAN_D1_UC_SER_EN,0 +CAN_D1_UC_SRV_BM,0 +CAN_D1_UC_SRV_RT,50 +CAN_LOGLEVEL,0 +CAN_P1_BITRATE,1000000 +CAN_P1_DRIVER,0 +CAN_P1_FDBITRATE,4 +CAN_P1_OPTIONS,0 +CAN_SLCAN_CPORT,0 +CAN_SLCAN_SDELAY,1 +CAN_SLCAN_SERNUM,-1 +CAN_SLCAN_TIMOUT,0 +CHUTE_ENABLED,0 +COMPASS_AUTO_ROT,2 +COMPASS_AUTODEC,1 +COMPASS_CAL_FIT,16 +COMPASS_DEC,0 +COMPASS_DEV_ID,0 +COMPASS_DEV_ID2,0 +COMPASS_DEV_ID3,0 +COMPASS_DEV_ID4,0 +COMPASS_DEV_ID5,0 +COMPASS_DEV_ID6,0 +COMPASS_DEV_ID7,0 +COMPASS_DEV_ID8,0 +COMPASS_DIA_X,1 +COMPASS_DIA_Y,1 +COMPASS_DIA_Z,1 +COMPASS_DIA2_X,1 +COMPASS_DIA2_Y,1 +COMPASS_DIA2_Z,1 +COMPASS_DIA3_X,1 +COMPASS_DIA3_Y,1 +COMPASS_DIA3_Z,1 +COMPASS_DISBLMSK,0 +COMPASS_ENABLE,1 +COMPASS_EXTERN2,0 +COMPASS_EXTERN3,0 +COMPASS_EXTERNAL,0 +COMPASS_FLTR_RNG,0 +COMPASS_LEARN,0 +COMPASS_MOT_X,0 +COMPASS_MOT_Y,0 +COMPASS_MOT_Z,0 +COMPASS_MOT2_X,0 +COMPASS_MOT2_Y,0 +COMPASS_MOT2_Z,0 +COMPASS_MOT3_X,0 +COMPASS_MOT3_Y,0 +COMPASS_MOT3_Z,0 +COMPASS_MOTCT,0 +COMPASS_ODI_X,0 +COMPASS_ODI_Y,0 +COMPASS_ODI_Z,0 +COMPASS_ODI2_X,0 +COMPASS_ODI2_Y,0 +COMPASS_ODI2_Z,0 +COMPASS_ODI3_X,0 +COMPASS_ODI3_Y,0 +COMPASS_ODI3_Z,0 +COMPASS_OFFS_MAX,1800 +COMPASS_OFS_X,0 +COMPASS_OFS_Y,0 +COMPASS_OFS_Z,0 +COMPASS_OFS2_X,0 +COMPASS_OFS2_Y,0 +COMPASS_OFS2_Z,0 +COMPASS_OFS3_X,0 +COMPASS_OFS3_Y,0 +COMPASS_OFS3_Z,0 +COMPASS_OPTIONS,0 +COMPASS_ORIENT,0 +COMPASS_ORIENT2,0 +COMPASS_ORIENT3,0 +COMPASS_PMOT_EN,0 +COMPASS_PRIO1_ID,0 +COMPASS_PRIO2_ID,0 +COMPASS_PRIO3_ID,0 +COMPASS_SCALE,0 +COMPASS_SCALE2,0 +COMPASS_SCALE3,0 +COMPASS_USE,1 +COMPASS_USE2,1 +COMPASS_USE3,1 +CRASH_ACC_THRESH,0 +CRASH_DETECT,0 +CRUISE_ALT_FLOOR,0 +CUST_ROT_ENABLE,0 +DSPOILER_AILMTCH,100 +DSPOILER_CROW_W1,0 +DSPOILER_CROW_W2,0 +DSPOILER_OPTS,3 +DSPOILR_RUD_RATE,100 +EAHRS_TYPE,0 +EFI_TYPE,0 +EK3_ABIAS_P_NSE,0.02 +EK3_ACC_BIAS_LIM,1 +EK3_ACC_P_NSE,0.35 +EK3_AFFINITY,0 +EK3_ALT_M_NSE,3 +EK3_BCN_DELAY,50 +EK3_BCN_I_GTE,500 +EK3_BCN_M_NSE,1 +EK3_BETA_MASK,0 +EK3_CHECK_SCALE,100 +EK3_DRAG_BCOEF_X,0 +EK3_DRAG_BCOEF_Y,0 +EK3_DRAG_M_NSE,0.5 +EK3_DRAG_MCOEF,0 +EK3_EAS_I_GATE,400 +EK3_EAS_M_NSE,1.4 +EK3_ENABLE,1 +EK3_ERR_THRESH,0.2 +EK3_FLOW_DELAY,10 +EK3_FLOW_I_GATE,500 +EK3_FLOW_M_NSE,0.15 +EK3_FLOW_USE,2 +EK3_GBIAS_P_NSE,0.001 +EK3_GLITCH_RAD,25 +EK3_GND_EFF_DZ,4 +EK3_GPS_CHECK,31 +EK3_GPS_VACC_MAX,0 +EK3_GSF_RST_MAX,2 +EK3_GSF_RUN_MASK,3 +EK3_GSF_USE_MASK,3 +EK3_GYRO_P_NSE,0.015 +EK3_HGT_DELAY,60 +EK3_HGT_I_GATE,500 +EK3_HRT_FILT,2 +EK3_IMU_MASK,3 +EK3_LOG_LEVEL,0 +EK3_MAG_CAL,0 +EK3_MAG_EF_LIM,50 +EK3_MAG_I_GATE,300 +EK3_MAG_M_NSE,0.05 +EK3_MAG_MASK,0 +EK3_MAGB_P_NSE,0.0001 +EK3_MAGE_P_NSE,0.001 +EK3_MAX_FLOW,2.5 +EK3_NOAID_M_NSE,10 +EK3_OGN_HGT_MASK,0 +EK3_OGNM_TEST_SF,2 +EK3_OPTIONS,0 +EK3_POS_I_GATE,500 +EK3_POSNE_M_NSE,0.5 +EK3_PRIMARY,0 +EK3_RNG_I_GATE,500 +EK3_RNG_M_NSE,0.5 +EK3_RNG_USE_HGT,-1 +EK3_RNG_USE_SPD,2 +EK3_SRC_OPTIONS,1 +EK3_SRC1_POSXY,3 +EK3_SRC1_POSZ,1 +EK3_SRC1_VELXY,3 +EK3_SRC1_VELZ,3 +EK3_SRC1_YAW,1 +EK3_SRC2_POSXY,0 +EK3_SRC2_POSZ,1 +EK3_SRC2_VELXY,0 +EK3_SRC2_VELZ,0 +EK3_SRC2_YAW,0 +EK3_SRC3_POSXY,0 +EK3_SRC3_POSZ,1 +EK3_SRC3_VELXY,0 +EK3_SRC3_VELZ,0 +EK3_SRC3_YAW,0 +EK3_TAU_OUTPUT,25 +EK3_TERR_GRAD,0.1 +EK3_VEL_I_GATE,500 +EK3_VELD_M_NSE,0.7 +EK3_VELNE_M_NSE,0.5 +EK3_VIS_VERR_MAX,0.9 +EK3_VIS_VERR_MIN,0.1 +EK3_WENC_VERR,0.1 +EK3_WIND_P_NSE,0.1 +EK3_WIND_PSCALE,1 +EK3_YAW_I_GATE,300 +EK3_YAW_M_NSE,0.5 +ESC_TLM_MAV_OFS,0 +FBWB_CLIMB_RATE,2 +FBWB_ELEV_REV,0 +FENCE_ACTION,1 +FENCE_ALT_MAX,100 +FENCE_ALT_MIN,-10 +FENCE_AUTOENABLE,0 +FENCE_ENABLE,0 +FENCE_MARGIN,2 +FENCE_OPTIONS,1 +FENCE_RADIUS,300 +FENCE_RET_ALT,0 +FENCE_RET_RALLY,0 +FENCE_TOTAL,0 +FENCE_TYPE,4 +FFT_ENABLE,0 +FILT1_TYPE,0 +FILT2_TYPE,0 +FILT3_TYPE,0 +FILT4_TYPE,0 +FILT5_TYPE,0 +FILT6_TYPE,0 +FILT7_TYPE,0 +FILT8_TYPE,0 +FLAP_1_PERCNT,0 +FLAP_1_SPEED,0 +FLAP_2_PERCNT,0 +FLAP_2_SPEED,0 +FLAP_SLEWRATE,75 +FLIGHT_OPTIONS,0 +FLOW_TYPE,0 +FLTMODE_CH,8 +FLTMODE_GCSBLOCK,0 +FLTMODE1,11 +FLTMODE2,11 +FLTMODE3,5 +FLTMODE4,5 +FLTMODE5,0 +FLTMODE6,0 +FOLL_ENABLE,0 +FORMAT_VERSION,13 +FRSKY_DNLINK_ID,27 +FRSKY_DNLINK1_ID,20 +FRSKY_DNLINK2_ID,7 +FRSKY_OPTIONS,0 +FRSKY_UPLINK_ID,13 +FS_EKF_THRESH,0.8 +FS_GCS_ENABL,0 +FS_LONG_ACTN,0 +FS_LONG_TIMEOUT,5 +FS_SHORT_ACTN,0 +FS_SHORT_TIMEOUT,1.5 +FWD_BAT_IDX,0 +FWD_BAT_VOLT_MAX,0 +FWD_BAT_VOLT_MIN,0 +GCS_PID_MASK,0 +GEN_TYPE,0 +GLIDE_SLOPE_MIN,15 +GLIDE_SLOPE_THR,5 +GPS_AUTO_CONFIG,1 +GPS_AUTO_SWITCH,1 +GPS_BLEND_MASK,5 +GPS_DRV_OPTIONS,0 +GPS_INJECT_TO,127 +GPS_MIN_ELEV,-100 +GPS_NAVFILTER,8 +GPS_PRIMARY,0 +GPS_RAW_DATA,0 +GPS_SAVE_CFG,2 +GPS_SBAS_MODE,2 +GPS_SBP_LOGMASK,-256 +GPS1_CAN_NODEID,0 +GPS1_CAN_OVRIDE,0 +GPS1_COM_PORT,1 +GPS1_DELAY_MS,0 +GPS1_GNSS_MODE,0 +GPS1_MB_TYPE,0 +GPS1_POS_X,0 +GPS1_POS_Y,0 +GPS1_POS_Z,0 +GPS1_RATE_MS,200 +GPS1_TYPE,1 +GPS2_TYPE,0 +GRIP_ENABLE,0 +GROUND_STEER_ALT,0 +GROUND_STEER_DPS,90 +GUIDED_D,0 +GUIDED_D_FF,0 +GUIDED_FF,0 +GUIDED_FLTD,5 +GUIDED_FLTE,5 +GUIDED_FLTT,5 +GUIDED_I,0 +GUIDED_IMAX,10 +GUIDED_NEF,0 +GUIDED_NTF,0 +GUIDED_P,5000 +GUIDED_PDMX,0 +GUIDED_SMAX,0 +HOME_RESET_ALT,0 +ICE_ENABLE,0 +INITIAL_MODE,0 +INS_ACC_BODYFIX,2 +INS_ACC_ID,0 +INS_ACC1_CALTEMP,-300 +INS_ACC2_CALTEMP,-300 +INS_ACC2_ID,0 +INS_ACC2OFFS_X,0 +INS_ACC2OFFS_Y,0 +INS_ACC2OFFS_Z,0 +INS_ACC2SCAL_X,1 +INS_ACC2SCAL_Y,1 +INS_ACC2SCAL_Z,1 +INS_ACC3_CALTEMP,-300 +INS_ACC3_ID,0 +INS_ACC3OFFS_X,0 +INS_ACC3OFFS_Y,0 +INS_ACC3OFFS_Z,0 +INS_ACC3SCAL_X,1 +INS_ACC3SCAL_Y,1 +INS_ACC3SCAL_Z,1 +INS_ACCEL_FILTER,20 +INS_ACCOFFS_X,0 +INS_ACCOFFS_Y,0 +INS_ACCOFFS_Z,0 +INS_ACCSCAL_X,1 +INS_ACCSCAL_Y,1 +INS_ACCSCAL_Z,1 +INS_ENABLE_MASK,127 +INS_FAST_SAMPLE,1 +INS_GYR_CAL,1 +INS_GYR_ID,0 +INS_GYR1_CALTEMP,-300 +INS_GYR2_CALTEMP,-300 +INS_GYR2_ID,0 +INS_GYR2OFFS_X,0 +INS_GYR2OFFS_Y,0 +INS_GYR2OFFS_Z,0 +INS_GYR3_CALTEMP,-300 +INS_GYR3_ID,0 +INS_GYR3OFFS_X,0 +INS_GYR3OFFS_Y,0 +INS_GYR3OFFS_Z,0 +INS_GYRO_FILTER,20 +INS_GYRO_RATE,1 +INS_GYROFFS_X,0 +INS_GYROFFS_Y,0 +INS_GYROFFS_Z,0 +INS_HNTC2_ENABLE,0 +INS_HNTCH_ATT,40 +INS_HNTCH_BW,40 +INS_HNTCH_ENABLE,1 +INS_HNTCH_FM_RAT,1 +INS_HNTCH_FREQ,80 +INS_HNTCH_HMNCS,3 +INS_HNTCH_MODE,1 +INS_HNTCH_OPTS,0 +INS_HNTCH_REF,0 +INS_LOG_BAT_CNT,1024 +INS_LOG_BAT_LGCT,32 +INS_LOG_BAT_LGIN,20 +INS_LOG_BAT_MASK,0 +INS_LOG_BAT_OPT,0 +INS_POS1_X,0 +INS_POS1_Y,0 +INS_POS1_Z,0 +INS_POS2_X,0 +INS_POS2_Y,0 +INS_POS2_Z,0 +INS_POS3_X,0 +INS_POS3_Y,0 +INS_POS3_Z,0 +INS_RAW_LOG_OPT,0 +INS_STILL_THRESH,0.1 +INS_TCAL_OPTIONS,0 +INS_TCAL1_ENABLE,0 +INS_TCAL2_ENABLE,0 +INS_TCAL3_ENABLE,0 +INS_TRIM_OPTION,1 +INS_USE,1 +INS_USE2,1 +INS_USE3,1 +KDE_NPOLE,14 +KFF_RDDRMIX,0.5 +KFF_THR2PTCH,0 +LAND_ABORT_DEG,0 +LAND_ABORT_THR,0 +LAND_DISARMDELAY,20 +LAND_FLAP_PERCNT,0 +LAND_FLARE_AIM,50 +LAND_FLARE_ALT,3 +LAND_FLARE_SEC,2 +LAND_OPTIONS,0 +LAND_PF_ALT,10 +LAND_PF_ARSPD,0 +LAND_PF_SEC,6 +LAND_PITCH_DEG,0 +LAND_SLOPE_RCALC,2 +LAND_THEN_NEUTRL,0 +LAND_THR_SLEW,0 +LAND_TYPE,0 +LAND_WIND_COMP,50 +LEVEL_ROLL_LIMIT,5 +LGR_ENABLE,0 +LOG_BACKEND_TYPE,1 +LOG_BITMASK,65535 +LOG_DARM_RATEMAX,0 +LOG_DISARMED,0 +LOG_FILE_BUFSIZE,200 +LOG_FILE_DSRMROT,0 +LOG_FILE_MB_FREE,500 +LOG_FILE_RATEMAX,0 +LOG_FILE_TIMEOUT,5 +LOG_MAV_BUFSIZE,8 +LOG_MAV_RATEMAX,0 +LOG_MAX_FILES,500 +LOG_REPLAY,0 +MAN_EXPO_PITCH,0 +MAN_EXPO_ROLL,0 +MAN_EXPO_RUDDER,0 +MANUAL_RCMASK,0 +MIN_GROUNDSPEED,0 +MIS_OPTIONS,0 +MIS_RESTART,0 +MIS_TOTAL,0 +MIXING_GAIN,0.5 +MIXING_OFFSET,0 +MNT1_TYPE,0 +MNT2_TYPE,0 +MSP_OPTIONS,0 +MSP_OSD_NCELLS,0 +NAVL1_DAMPING,0.75 +NAVL1_LIM_BANK,0 +NAVL1_PERIOD,17 +NAVL1_XTRACK_I,0.02 +NMEA_MSG_EN,3 +NMEA_RATE_MS,100 +NTF_BUZZ_ON_LVL,1 +NTF_BUZZ_PIN,32 +NTF_BUZZ_TYPES,5 +NTF_BUZZ_VOLUME,100 +NTF_DISPLAY_TYPE,0 +NTF_LED_BRIGHT,3 +NTF_LED_LEN,1 +NTF_LED_OVERRIDE,0 +NTF_LED_TYPES,123079 +ONESHOT_MASK,0 +OSD_ARM_SCR,0 +OSD_BTN_DELAY,300 +OSD_CELL_COUNT,-1 +OSD_CHAN,0 +OSD_DSARM_SCR,0 +OSD_FONT,0 +OSD_FS_SCR,0 +OSD_H_OFFSET,32 +OSD_MSG_TIME,10 +OSD_OPTIONS,1 +OSD_SB_H_OFS,0 +OSD_SB_V_EXT,0 +OSD_SW_METHOD,0 +OSD_TYPE,1 +OSD_TYPE2,0 +OSD_UNITS,0 +OSD_V_OFFSET,16 +OSD_W_ACRVOLT,3.6 +OSD_W_AVGCELLV,3.6 +OSD_W_BATVOLT,10 +OSD_W_NSAT,9 +OSD_W_RESTVOLT,10 +OSD_W_RSSI,30 +OSD_W_TERR,-1 +OSD1_ACRVOLT_EN,0 +OSD1_ACRVOLT_X,24 +OSD1_ACRVOLT_Y,4 +OSD1_ALTITUDE_EN,1 +OSD1_ALTITUDE_X,23 +OSD1_ALTITUDE_Y,8 +OSD1_ARMING_EN,1 +OSD1_ARMING_X,1 +OSD1_ARMING_Y,1 +OSD1_ASPD1_EN,0 +OSD1_ASPD1_X,0 +OSD1_ASPD1_Y,0 +OSD1_ASPD2_EN,0 +OSD1_ASPD2_X,0 +OSD1_ASPD2_Y,0 +OSD1_ASPEED_EN,0 +OSD1_ASPEED_X,2 +OSD1_ASPEED_Y,13 +OSD1_ATEMP_EN,0 +OSD1_ATEMP_X,0 +OSD1_ATEMP_Y,0 +OSD1_AVGCELLV_EN,0 +OSD1_AVGCELLV_X,24 +OSD1_AVGCELLV_Y,3 +OSD1_BAT_VOLT_EN,1 +OSD1_BAT_VOLT_X,24 +OSD1_BAT_VOLT_Y,1 +OSD1_BAT2_VLT_EN,0 +OSD1_BAT2_VLT_X,0 +OSD1_BAT2_VLT_Y,0 +OSD1_BAT2USED_EN,0 +OSD1_BAT2USED_X,0 +OSD1_BAT2USED_Y,0 +OSD1_BATTBAR_EN,1 +OSD1_BATTBAR_X,1 +OSD1_BATTBAR_Y,1 +OSD1_BATUSED_EN,1 +OSD1_BATUSED_X,23 +OSD1_BATUSED_Y,3 +OSD1_BTEMP_EN,0 +OSD1_BTEMP_X,0 +OSD1_BTEMP_Y,0 +OSD1_CALLSIGN_EN,0 +OSD1_CALLSIGN_X,0 +OSD1_CALLSIGN_Y,0 +OSD1_CELLVOLT_EN,1 +OSD1_CELLVOLT_X,1 +OSD1_CELLVOLT_Y,1 +OSD1_CHAN_MAX,2100 +OSD1_CHAN_MIN,900 +OSD1_CLIMBEFF_EN,0 +OSD1_CLIMBEFF_X,0 +OSD1_CLIMBEFF_Y,0 +OSD1_CLK_EN,0 +OSD1_CLK_X,0 +OSD1_CLK_Y,0 +OSD1_COMPASS_EN,1 +OSD1_COMPASS_X,15 +OSD1_COMPASS_Y,3 +OSD1_CRSSHAIR_EN,0 +OSD1_CRSSHAIR_X,0 +OSD1_CRSSHAIR_Y,0 +OSD1_CURRENT_EN,1 +OSD1_CURRENT_X,25 +OSD1_CURRENT_Y,2 +OSD1_CURRENT2_EN,0 +OSD1_CURRENT2_X,0 +OSD1_CURRENT2_Y,0 +OSD1_DIST_EN,0 +OSD1_DIST_X,22 +OSD1_DIST_Y,11 +OSD1_EFF_EN,0 +OSD1_EFF_X,22 +OSD1_EFF_Y,10 +OSD1_ENABLE,1 +OSD1_ESC_IDX,0 +OSD1_ESCAMPS_EN,0 +OSD1_ESCAMPS_X,24 +OSD1_ESCAMPS_Y,14 +OSD1_ESCRPM_EN,0 +OSD1_ESCRPM_X,22 +OSD1_ESCRPM_Y,12 +OSD1_ESCTEMP_EN,0 +OSD1_ESCTEMP_X,24 +OSD1_ESCTEMP_Y,13 +OSD1_FENCE_EN,0 +OSD1_FENCE_X,14 +OSD1_FENCE_Y,9 +OSD1_FLTIME_EN,0 +OSD1_FLTIME_X,23 +OSD1_FLTIME_Y,10 +OSD1_FLTMODE_EN,1 +OSD1_FLTMODE_X,2 +OSD1_FLTMODE_Y,8 +OSD1_FONT,0 +OSD1_GPSLAT_EN,1 +OSD1_GPSLAT_X,9 +OSD1_GPSLAT_Y,13 +OSD1_GPSLONG_EN,1 +OSD1_GPSLONG_X,9 +OSD1_GPSLONG_Y,14 +OSD1_GSPEED_EN,1 +OSD1_GSPEED_X,2 +OSD1_GSPEED_Y,14 +OSD1_HDOP_EN,0 +OSD1_HDOP_X,0 +OSD1_HDOP_Y,0 +OSD1_HEADING_EN,1 +OSD1_HEADING_X,13 +OSD1_HEADING_Y,2 +OSD1_HOME_EN,1 +OSD1_HOME_X,14 +OSD1_HOME_Y,1 +OSD1_HOMEDIR_EN,1 +OSD1_HOMEDIR_X,1 +OSD1_HOMEDIR_Y,1 +OSD1_HOMEDIST_EN,1 +OSD1_HOMEDIST_X,1 +OSD1_HOMEDIST_Y,1 +OSD1_HORIZON_EN,1 +OSD1_HORIZON_X,14 +OSD1_HORIZON_Y,8 +OSD1_LINK_Q_EN,0 +OSD1_LINK_Q_X,1 +OSD1_LINK_Q_Y,1 +OSD1_MESSAGE_EN,1 +OSD1_MESSAGE_X,2 +OSD1_MESSAGE_Y,6 +OSD1_PITCH_EN,0 +OSD1_PITCH_X,0 +OSD1_PITCH_Y,0 +OSD1_PLUSCODE_EN,0 +OSD1_PLUSCODE_X,0 +OSD1_PLUSCODE_Y,0 +OSD1_POWER_EN,1 +OSD1_POWER_X,1 +OSD1_POWER_Y,1 +OSD1_RESTVOLT_EN,0 +OSD1_RESTVOLT_X,24 +OSD1_RESTVOLT_Y,2 +OSD1_RNGF_EN,0 +OSD1_RNGF_X,0 +OSD1_RNGF_Y,0 +OSD1_ROLL_EN,0 +OSD1_ROLL_X,0 +OSD1_ROLL_Y,0 +OSD1_RPM_EN,0 +OSD1_RPM_X,2 +OSD1_RPM_Y,2 +OSD1_RSSI_EN,1 +OSD1_RSSI_X,1 +OSD1_RSSI_Y,1 +OSD1_SATS_EN,1 +OSD1_SATS_X,1 +OSD1_SATS_Y,3 +OSD1_SIDEBARS_EN,0 +OSD1_SIDEBARS_X,4 +OSD1_SIDEBARS_Y,5 +OSD1_STATS_EN,0 +OSD1_STATS_X,0 +OSD1_STATS_Y,0 +OSD1_TEMP_EN,0 +OSD1_TEMP_X,0 +OSD1_TEMP_Y,0 +OSD1_TER_HGT_EN,0 +OSD1_TER_HGT_X,23 +OSD1_TER_HGT_Y,7 +OSD1_THROTTLE_EN,1 +OSD1_THROTTLE_X,24 +OSD1_THROTTLE_Y,11 +OSD1_TXT_RES,0 +OSD1_VSPEED_EN,1 +OSD1_VSPEED_X,24 +OSD1_VSPEED_Y,9 +OSD1_VTX_PWR_EN,0 +OSD1_VTX_PWR_X,0 +OSD1_VTX_PWR_Y,0 +OSD1_WAYPOINT_EN,0 +OSD1_WAYPOINT_X,0 +OSD1_WAYPOINT_Y,0 +OSD1_WIND_EN,0 +OSD1_WIND_X,2 +OSD1_WIND_Y,12 +OSD1_XTRACK_EN,0 +OSD1_XTRACK_X,0 +OSD1_XTRACK_Y,0 +OSD2_ENABLE,0 +OSD2_ESC_IDX,0 +OSD2_FONT,0 +OSD2_LINK_Q_EN,0 +OSD2_LINK_Q_X,1 +OSD2_LINK_Q_Y,1 +OSD2_TXT_RES,0 +OSD3_ENABLE,0 +OSD3_ESC_IDX,0 +OSD3_FONT,0 +OSD3_LINK_Q_EN,0 +OSD3_LINK_Q_X,1 +OSD3_LINK_Q_Y,1 +OSD3_TXT_RES,0 +OSD4_ENABLE,0 +OSD4_ESC_IDX,0 +OSD4_FONT,0 +OSD4_LINK_Q_EN,0 +OSD4_LINK_Q_X,1 +OSD4_LINK_Q_Y,1 +OSD4_TXT_RES,0 +OSD5_ENABLE,0 +OSD6_ENABLE,0 +PLND_ENABLED,0 +PTCH_LIM_MAX_DEG,20 +PTCH_LIM_MIN_DEG,-25 +PTCH_RATE_D,0 +PTCH_RATE_D_FF,0 +PTCH_RATE_FF,0.345 +PTCH_RATE_FLTD,12 +PTCH_RATE_FLTE,0 +PTCH_RATE_FLTT,3 +PTCH_RATE_I,0.15 +PTCH_RATE_IMAX,0.666 +PTCH_RATE_NEF,0 +PTCH_RATE_NTF,0 +PTCH_RATE_P,0.04 +PTCH_RATE_PDMX,0 +PTCH_RATE_SMAX,150 +PTCH_TRIM_DEG,0 +PTCH2SRV_RLL,1 +PTCH2SRV_RMAX_DN,0 +PTCH2SRV_RMAX_UP,0 +PTCH2SRV_TCONST,0.5 +Q_A_ACCEL_P_MAX,40000 +Q_A_ACCEL_R_MAX,40000 +Q_A_ACCEL_Y_MAX,10000 +Q_A_ANG_LIM_TC,1 +Q_A_ANG_PIT_P,4.5 +Q_A_ANG_RLL_P,4.5 +Q_A_ANG_YAW_P,4.5 +Q_A_ANGLE_BOOST,1 +Q_A_INPUT_TC,0.2 +Q_A_LAND_P_MULT,1 +Q_A_LAND_R_MULT,1 +Q_A_LAND_Y_MULT,1 +Q_A_RAT_PIT_D,0.0036 +Q_A_RAT_PIT_D_FF,0 +Q_A_RAT_PIT_FF,0 +Q_A_RAT_PIT_FLTD,10 +Q_A_RAT_PIT_FLTE,0 +Q_A_RAT_PIT_FLTT,20 +Q_A_RAT_PIT_I,0.25 +Q_A_RAT_PIT_IMAX,0.5 +Q_A_RAT_PIT_NEF,0 +Q_A_RAT_PIT_NTF,0 +Q_A_RAT_PIT_P,0.25 +Q_A_RAT_PIT_PDMX,0 +Q_A_RAT_PIT_SMAX,50 +Q_A_RAT_RLL_D,0.0036 +Q_A_RAT_RLL_D_FF,0 +Q_A_RAT_RLL_FF,0 +Q_A_RAT_RLL_FLTD,10 +Q_A_RAT_RLL_FLTE,0 +Q_A_RAT_RLL_FLTT,20 +Q_A_RAT_RLL_I,0.25 +Q_A_RAT_RLL_IMAX,0.5 +Q_A_RAT_RLL_NEF,0 +Q_A_RAT_RLL_NTF,0 +Q_A_RAT_RLL_P,0.25 +Q_A_RAT_RLL_PDMX,0 +Q_A_RAT_RLL_SMAX,50 +Q_A_RAT_YAW_D,0 +Q_A_RAT_YAW_D_FF,0 +Q_A_RAT_YAW_FF,0 +Q_A_RAT_YAW_FLTD,20 +Q_A_RAT_YAW_FLTE,2.5 +Q_A_RAT_YAW_FLTT,20 +Q_A_RAT_YAW_I,0.018 +Q_A_RAT_YAW_IMAX,0.5 +Q_A_RAT_YAW_NEF,0 +Q_A_RAT_YAW_NTF,0 +Q_A_RAT_YAW_P,0.18 +Q_A_RAT_YAW_PDMX,0 +Q_A_RAT_YAW_SMAX,50 +Q_A_RATE_FF_ENAB,1 +Q_A_RATE_P_MAX,75 +Q_A_RATE_R_MAX,75 +Q_A_RATE_Y_MAX,75 +Q_A_SLEW_YAW,6000 +Q_A_THR_G_BOOST,0 +Q_A_THR_MIX_MAN,0.1 +Q_A_THR_MIX_MAX,0.5 +Q_A_THR_MIX_MIN,0.1 +Q_ACRO_PIT_RATE,180 +Q_ACRO_RLL_RATE,360 +Q_ACRO_YAW_RATE,90 +Q_ANGLE_MAX,3000 +Q_APPROACH_DIST,0 +Q_ASSIST_ALT,0 +Q_ASSIST_ANGLE,30 +Q_ASSIST_DELAY,0.5 +Q_ASSIST_OPTIONS,0 +Q_ASSIST_SPEED,0 +Q_BACKTRANS_MS,3000 +Q_BCK_PIT_LIM,10 +Q_ENABLE,1 +Q_ESC_CAL,0 +Q_FRAME_CLASS,1 +Q_FRAME_TYPE,1 +Q_FW_LND_APR_RAD,0 +Q_FWD_MANTHR_MAX,0 +Q_FWD_PIT_LIM,3 +Q_FWD_THR_GAIN,2 +Q_FWD_THR_USE,0 +Q_GUIDED_MODE,0 +Q_LAND_ALTCHG,0.2 +Q_LAND_FINAL_ALT,6 +Q_LAND_FINAL_SPD,0.5 +Q_LAND_ICE_CUT,1 +Q_LOIT_ACC_MAX,250 +Q_LOIT_ANG_MAX,15 +Q_LOIT_BRK_ACCEL,50 +Q_LOIT_BRK_DELAY,1 +Q_LOIT_BRK_JERK,250 +Q_LOIT_SPEED,500 +Q_M_BAT_CURR_MAX,0 +Q_M_BAT_CURR_TC,5 +Q_M_BAT_IDX,0 +Q_M_BAT_VOLT_MAX,0 +Q_M_BAT_VOLT_MIN,0 +Q_M_BOOST_SCALE,0 +Q_M_HOVER_LEARN,2 +Q_M_OPTIONS,0 +Q_M_PWM_MAX,2000 +Q_M_PWM_MIN,1000 +Q_M_PWM_TYPE,0 +Q_M_SAFE_DISARM,0 +Q_M_SAFE_TIME,1 +Q_M_SLEW_DN_TIME,0 +Q_M_SLEW_UP_TIME,0 +Q_M_SPIN_ARM,0.1 +Q_M_SPIN_MAX,0.95 +Q_M_SPIN_MIN,0.15 +Q_M_SPOOL_TIM_DN,0 +Q_M_SPOOL_TIME,0.25 +Q_M_THST_EXPO,0.65 +Q_M_THST_HOVER,0.35 +Q_M_YAW_HEADROOM,200 +Q_MAV_TYPE,0 +Q_NAVALT_MIN,0 +Q_OPTIONS,0 +Q_P_ACCZ_D,0 +Q_P_ACCZ_D_FF,0 +Q_P_ACCZ_FF,0 +Q_P_ACCZ_FLTD,0 +Q_P_ACCZ_FLTE,10 +Q_P_ACCZ_FLTT,0 +Q_P_ACCZ_I,1 +Q_P_ACCZ_IMAX,800 +Q_P_ACCZ_NEF,0 +Q_P_ACCZ_NTF,0 +Q_P_ACCZ_P,0.3 +Q_P_ACCZ_PDMX,0 +Q_P_ACCZ_SMAX,0 +Q_P_ANGLE_MAX,0 +Q_P_JERK_XY,2 +Q_P_JERK_Z,5 +Q_P_POSXY_P,0.5 +Q_P_POSZ_P,1 +Q_P_VELXY_D,0.17 +Q_P_VELXY_FF,0 +Q_P_VELXY_FLTD,5 +Q_P_VELXY_FLTE,5 +Q_P_VELXY_I,0.35 +Q_P_VELXY_IMAX,1000 +Q_P_VELXY_P,0.7 +Q_P_VELZ_D,0 +Q_P_VELZ_FF,0 +Q_P_VELZ_FLTD,5 +Q_P_VELZ_FLTE,5 +Q_P_VELZ_I,0 +Q_P_VELZ_IMAX,1000 +Q_P_VELZ_P,5 +Q_PILOT_ACCEL_Z,2.5 +Q_PILOT_SPD_DN,0 +Q_PILOT_SPD_UP,2.5 +Q_PLT_Y_EXPO,0.25 +Q_PLT_Y_RATE,100 +Q_PLT_Y_RATE_TC,0.25 +Q_RC_SPEED,490 +Q_RTL_ALT,15 +Q_RTL_ALT_MIN,10 +Q_RTL_MODE,0 +Q_TAILSIT_ANG_VT,0 +Q_TAILSIT_ANGLE,45 +Q_TAILSIT_DSKLD,0 +Q_TAILSIT_ENABLE,2 +Q_TAILSIT_GSCMAX,2 +Q_TAILSIT_GSCMIN,0.4 +Q_TAILSIT_GSCMSK,1 +Q_TAILSIT_INPUT,0 +Q_TAILSIT_MIN_VO,0 +Q_TAILSIT_MOTMX,0 +Q_TAILSIT_RAT_FW,50 +Q_TAILSIT_RAT_VT,50 +Q_TAILSIT_RLL_MX,0 +Q_TAILSIT_THR_VT,-1 +Q_TAILSIT_VFGAIN,0 +Q_TAILSIT_VHGAIN,0.5 +Q_TAILSIT_VHPOW,2.5 +Q_TAILSIT_VT_P_P,1 +Q_TAILSIT_VT_R_P,1 +Q_TAILSIT_VT_Y_P,1 +Q_THROTTLE_EXPO,0.2 +Q_TILT_ENABLE,0 +Q_TKOFF_ARSP_LIM,0 +Q_TKOFF_FAIL_SCL,0 +Q_TRAN_PIT_MAX,3 +Q_TRANS_DECEL,2 +Q_TRANS_FAIL,0 +Q_TRANS_FAIL_ACT,0 +Q_TRANSITION_MS,5000 +Q_TRIM_PITCH,0 +Q_VFWD_ALT,0 +Q_VFWD_GAIN,0 +Q_WP_ACCEL,100 +Q_WP_ACCEL_C,0 +Q_WP_ACCEL_Z,100 +Q_WP_JERK,1 +Q_WP_RADIUS,200 +Q_WP_RFND_USE,1 +Q_WP_SPEED,500 +Q_WP_SPEED_DN,150 +Q_WP_SPEED_UP,250 +Q_WP_TER_MARGIN,10 +Q_WVANE_ANG_MIN,1 +Q_WVANE_ENABLE,1 +Q_WVANE_GAIN,0 +Q_WVANE_HGT_MIN,0 +Q_WVANE_LAND,-1 +Q_WVANE_OPTIONS,0 +Q_WVANE_SPD_MAX,0 +Q_WVANE_TAKEOFF,-1 +Q_WVANE_VELZ_MAX,0 +QWIK_ANGLE_MAX,10 +QWIK_AUTO_FILTER,1 +QWIK_AUTO_SAVE,0 +QWIK_AXES,7 +QWIK_DOUBLE_TIME,10 +QWIK_ENABLE,0 +QWIK_GAIN_MARGIN,60 +QWIK_OPTIONS,0 +QWIK_OSC_SMAX,4 +QWIK_REDUCE_MAX,20 +QWIK_RP_PI_RATIO,1 +QWIK_Y_PI_RATIO,10 +QWIK_YAW_D_MAX,0.01 +QWIK_YAW_P_MAX,0.5 +RALLY_INCL_HOME,0 +RALLY_LIMIT_KM,5 +RALLY_TOTAL,0 +RC_OPTIONS,32 +RC_OVERRIDE_TIME,3 +RC_PROTOCOLS,1 +RC1_DZ,30 +RC1_MAX,1900 +RC1_MIN,1100 +RC1_OPTION,0 +RC1_REVERSED,0 +RC1_TRIM,1500 +RC10_DZ,0 +RC10_MAX,1900 +RC10_MIN,1100 +RC10_OPTION,0 +RC10_REVERSED,0 +RC10_TRIM,1500 +RC11_DZ,0 +RC11_MAX,1900 +RC11_MIN,1100 +RC11_OPTION,0 +RC11_REVERSED,0 +RC11_TRIM,1500 +RC12_DZ,0 +RC12_MAX,1900 +RC12_MIN,1100 +RC12_OPTION,0 +RC12_REVERSED,0 +RC12_TRIM,1500 +RC13_DZ,0 +RC13_MAX,1900 +RC13_MIN,1100 +RC13_OPTION,0 +RC13_REVERSED,0 +RC13_TRIM,1500 +RC14_DZ,0 +RC14_MAX,1900 +RC14_MIN,1100 +RC14_OPTION,0 +RC14_REVERSED,0 +RC14_TRIM,1500 +RC15_DZ,0 +RC15_MAX,1900 +RC15_MIN,1100 +RC15_OPTION,0 +RC15_REVERSED,0 +RC15_TRIM,1500 +RC16_DZ,0 +RC16_MAX,1900 +RC16_MIN,1100 +RC16_OPTION,0 +RC16_REVERSED,0 +RC16_TRIM,1500 +RC2_DZ,30 +RC2_MAX,1900 +RC2_MIN,1100 +RC2_OPTION,0 +RC2_REVERSED,0 +RC2_TRIM,1500 +RC3_DZ,30 +RC3_MAX,1900 +RC3_MIN,1100 +RC3_OPTION,0 +RC3_REVERSED,0 +RC3_TRIM,1500 +RC4_DZ,30 +RC4_MAX,1900 +RC4_MIN,1100 +RC4_OPTION,0 +RC4_REVERSED,0 +RC4_TRIM,1500 +RC5_DZ,0 +RC5_MAX,1900 +RC5_MIN,1100 +RC5_OPTION,0 +RC5_REVERSED,0 +RC5_TRIM,1500 +RC6_DZ,0 +RC6_MAX,1900 +RC6_MIN,1100 +RC6_OPTION,0 +RC6_REVERSED,0 +RC6_TRIM,1500 +RC7_DZ,0 +RC7_MAX,1900 +RC7_MIN,1100 +RC7_OPTION,0 +RC7_REVERSED,0 +RC7_TRIM,1500 +RC8_DZ,0 +RC8_MAX,1900 +RC8_MIN,1100 +RC8_OPTION,0 +RC8_REVERSED,0 +RC8_TRIM,1500 +RC9_DZ,0 +RC9_MAX,1900 +RC9_MIN,1100 +RC9_OPTION,0 +RC9_REVERSED,0 +RC9_TRIM,1500 +RCMAP_PITCH,2 +RCMAP_ROLL,1 +RCMAP_THROTTLE,3 +RCMAP_YAW,4 +RELAY1_DEFAULT,0 +RELAY1_FUNCTION,0 +RELAY1_INVERTED,0 +RELAY1_PIN,-1 +RELAY2_FUNCTION,0 +RELAY3_FUNCTION,0 +RELAY4_FUNCTION,0 +RELAY5_FUNCTION,0 +RELAY6_FUNCTION,0 +RLL_RATE_D,0 +RLL_RATE_D_FF,0 +RLL_RATE_FF,0.345 +RLL_RATE_FLTD,12 +RLL_RATE_FLTE,0 +RLL_RATE_FLTT,3 +RLL_RATE_I,0.15 +RLL_RATE_IMAX,0.666 +RLL_RATE_NEF,0 +RLL_RATE_NTF,0 +RLL_RATE_P,0.08 +RLL_RATE_PDMX,0 +RLL_RATE_SMAX,150 +RLL2SRV_RMAX,0 +RLL2SRV_TCONST,0.5 +RNGFND_LANDING,0 +RNGFND_LND_ORNT,25 +RNGFND1_ADDR,0 +RNGFND1_FUNCTION,0 +RNGFND1_GNDCLEAR,10 +RNGFND1_MAX_CM,700 +RNGFND1_MIN_CM,20 +RNGFND1_OFFSET,0 +RNGFND1_ORIENT,25 +RNGFND1_PIN,-1 +RNGFND1_POS_X,0 +RNGFND1_POS_Y,0 +RNGFND1_POS_Z,0 +RNGFND1_PWRRNG,0 +RNGFND1_RMETRIC,1 +RNGFND1_SCALING,3 +RNGFND1_STOP_PIN,-1 +RNGFND1_TYPE,0 +RNGFND2_TYPE,0 +RNGFND3_TYPE,0 +RNGFND4_TYPE,0 +RNGFND5_TYPE,0 +RNGFND6_TYPE,0 +RNGFND7_TYPE,0 +RNGFND8_TYPE,0 +RNGFND9_TYPE,0 +RNGFNDA_TYPE,0 +ROLL_LIMIT_DEG,45 +RPM1_TYPE,0 +RPM2_TYPE,0 +RSSI_ANA_PIN,8 +RSSI_CHAN_HIGH,2000 +RSSI_CHAN_LOW,1000 +RSSI_CHANNEL,0 +RSSI_PIN_HIGH,5 +RSSI_PIN_LOW,0 +RSSI_TYPE,0 +RTL_ALTITUDE,100 +RTL_AUTOLAND,0 +RTL_CLIMB_MIN,0 +RTL_RADIUS,0 +RUDD_DT_GAIN,10 +RUDDER_ONLY,0 +SCALING_SPEED,15 +SCHED_DEBUG,0 +SCHED_LOOP_RATE,300 +SCHED_OPTIONS,0 +SCR_DEBUG_OPTS,0 +SCR_DIR_DISABLE,0 +SCR_ENABLE,1 +SCR_HEAP_SIZE,204800 +SCR_LD_CHECKSUM,-1 +SCR_RUN_CHECKSUM,-1 +SCR_SDEV_EN,0 +SCR_SDEV1_PROTO,-1 +SCR_SDEV2_PROTO,-1 +SCR_SDEV3_PROTO,-1 +SCR_THD_PRIORITY,0 +SCR_USER1,0 +SCR_USER2,0 +SCR_USER3,0 +SCR_USER4,0 +SCR_USER5,0 +SCR_USER6,0 +SCR_VM_I_COUNT,10000 +SERIAL_PASS1,0 +SERIAL_PASS2,-1 +SERIAL_PASSTIMO,15 +SERIAL0_BAUD,115 +SERIAL0_PROTOCOL,2 +SERIAL1_BAUD,57 +SERIAL1_OPTIONS,0 +SERIAL1_PROTOCOL,2 +SERIAL2_BAUD,57 +SERIAL2_OPTIONS,0 +SERIAL2_PROTOCOL,2 +SERIAL3_BAUD,230 +SERIAL3_OPTIONS,0 +SERIAL3_PROTOCOL,5 +SERIAL4_BAUD,230 +SERIAL4_OPTIONS,0 +SERIAL4_PROTOCOL,5 +SERIAL5_BAUD,115 +SERIAL5_OPTIONS,0 +SERIAL5_PROTOCOL,-1 +SERIAL6_BAUD,57 +SERIAL6_OPTIONS,0 +SERIAL6_PROTOCOL,-1 +SERIAL7_BAUD,57 +SERIAL7_OPTIONS,0 +SERIAL7_PROTOCOL,-1 +SERIAL8_BAUD,115200 +SERIAL8_OPTIONS,0 +SERIAL8_PROTOCOL,2 +SERVO_32_ENABLE,0 +SERVO_AUTO_TRIM,0 +SERVO_BLH_3DMASK,0 +SERVO_BLH_AUTO,0 +SERVO_BLH_BDMASK,0 +SERVO_BLH_DEBUG,0 +SERVO_BLH_MASK,0 +SERVO_BLH_OTYPE,0 +SERVO_BLH_POLES,14 +SERVO_BLH_PORT,0 +SERVO_BLH_RVMASK,0 +SERVO_BLH_TEST,0 +SERVO_BLH_TMOUT,0 +SERVO_BLH_TRATE,10 +SERVO_DSHOT_ESC,0 +SERVO_DSHOT_RATE,0 +SERVO_FTW_MASK,0 +SERVO_FTW_POLES,14 +SERVO_FTW_RVMASK,0 +SERVO_GPIO_MASK,0 +SERVO_RATE,50 +SERVO_RC_FS_MSK,0 +SERVO_ROB_POSMAX,4095 +SERVO_ROB_POSMIN,0 +SERVO_SBUS_RATE,50 +SERVO_VOLZ_MASK,0 +SERVO_VOLZ_RANGE,200 +SERVO1_FUNCTION,4 +SERVO1_MAX,2000 +SERVO1_MIN,1000 +SERVO1_REVERSED,0 +SERVO1_TRIM,1000 +SERVO10_FUNCTION,0 +SERVO10_MAX,1900 +SERVO10_MIN,1100 +SERVO10_REVERSED,0 +SERVO10_TRIM,1500 +SERVO11_FUNCTION,0 +SERVO11_MAX,1900 +SERVO11_MIN,1100 +SERVO11_REVERSED,0 +SERVO11_TRIM,1500 +SERVO12_FUNCTION,0 +SERVO12_MAX,1900 +SERVO12_MIN,1100 +SERVO12_REVERSED,0 +SERVO12_TRIM,1500 +SERVO13_FUNCTION,0 +SERVO13_MAX,1900 +SERVO13_MIN,1100 +SERVO13_REVERSED,0 +SERVO13_TRIM,1500 +SERVO14_FUNCTION,0 +SERVO14_MAX,1900 +SERVO14_MIN,1100 +SERVO14_REVERSED,0 +SERVO14_TRIM,1500 +SERVO15_FUNCTION,0 +SERVO15_MAX,1900 +SERVO15_MIN,1100 +SERVO15_REVERSED,0 +SERVO15_TRIM,1500 +SERVO16_FUNCTION,0 +SERVO16_MAX,1900 +SERVO16_MIN,1100 +SERVO16_REVERSED,0 +SERVO16_TRIM,1500 +SERVO2_FUNCTION,19 +SERVO2_MAX,2000 +SERVO2_MIN,1000 +SERVO2_REVERSED,0 +SERVO2_TRIM,1000 +SERVO3_FUNCTION,70 +SERVO3_MAX,2000 +SERVO3_MIN,1000 +SERVO3_REVERSED,0 +SERVO3_TRIM,1000 +SERVO4_FUNCTION,21 +SERVO4_MAX,2000 +SERVO4_MIN,1000 +SERVO4_REVERSED,0 +SERVO4_TRIM,1000 +SERVO5_FUNCTION,0 +SERVO5_MAX,1900 +SERVO5_MIN,1100 +SERVO5_REVERSED,0 +SERVO5_TRIM,1500 +SERVO6_FUNCTION,0 +SERVO6_MAX,1900 +SERVO6_MIN,1100 +SERVO6_REVERSED,0 +SERVO6_TRIM,1500 +SERVO7_FUNCTION,0 +SERVO7_MAX,1900 +SERVO7_MIN,1100 +SERVO7_REVERSED,0 +SERVO7_TRIM,1500 +SERVO8_FUNCTION,0 +SERVO8_MAX,1900 +SERVO8_MIN,1100 +SERVO8_REVERSED,0 +SERVO8_TRIM,1500 +SERVO9_FUNCTION,0 +SERVO9_MAX,1900 +SERVO9_MIN,1100 +SERVO9_REVERSED,0 +SERVO9_TRIM,1500 +SOAR_ENABLE,0 +SR0_ADSB,5 +SR0_EXT_STAT,1 +SR0_EXTRA1,1 +SR0_EXTRA2,1 +SR0_EXTRA3,1 +SR0_PARAMS,10 +SR0_POSITION,1 +SR0_RAW_CTRL,1 +SR0_RAW_SENS,1 +SR0_RC_CHAN,1 +SR1_ADSB,5 +SR1_EXT_STAT,1 +SR1_EXTRA1,1 +SR1_EXTRA2,1 +SR1_EXTRA3,1 +SR1_PARAMS,10 +SR1_POSITION,1 +SR1_RAW_CTRL,1 +SR1_RAW_SENS,1 +SR1_RC_CHAN,1 +SR2_ADSB,5 +SR2_EXT_STAT,1 +SR2_EXTRA1,1 +SR2_EXTRA2,1 +SR2_EXTRA3,1 +SR2_PARAMS,10 +SR2_POSITION,1 +SR2_RAW_CTRL,1 +SR2_RAW_SENS,1 +SR2_RC_CHAN,1 +SR3_ADSB,5 +SR3_EXT_STAT,1 +SR3_EXTRA1,1 +SR3_EXTRA2,1 +SR3_EXTRA3,1 +SR3_PARAMS,10 +SR3_POSITION,1 +SR3_RAW_CTRL,1 +SR3_RAW_SENS,1 +SR3_RC_CHAN,1 +SR4_ADSB,5 +SR4_EXT_STAT,1 +SR4_EXTRA1,1 +SR4_EXTRA2,1 +SR4_EXTRA3,1 +SR4_PARAMS,10 +SR4_POSITION,1 +SR4_RAW_CTRL,1 +SR4_RAW_SENS,1 +SR4_RC_CHAN,1 +SR5_ADSB,5 +SR5_EXT_STAT,1 +SR5_EXTRA1,1 +SR5_EXTRA2,1 +SR5_EXTRA3,1 +SR5_PARAMS,10 +SR5_POSITION,1 +SR5_RAW_CTRL,1 +SR5_RAW_SENS,1 +SR5_RC_CHAN,1 +SR6_ADSB,5 +SR6_EXT_STAT,1 +SR6_EXTRA1,1 +SR6_EXTRA2,1 +SR6_EXTRA3,1 +SR6_PARAMS,10 +SR6_POSITION,1 +SR6_RAW_CTRL,1 +SR6_RAW_SENS,1 +SR6_RC_CHAN,1 +STAB_PITCH_DOWN,2 +STALL_PREVENTION,1 +STAT_BOOTCNT,0 +STAT_FLTTIME,0 +STAT_RESET,1 +STAT_RUNTIME,0 +STEER2SRV_D,0.005 +STEER2SRV_DRTFCT,10 +STEER2SRV_DRTMIN,4500 +STEER2SRV_DRTSPD,0 +STEER2SRV_FF,0 +STEER2SRV_I,0.2 +STEER2SRV_IMAX,1500 +STEER2SRV_MINSPD,1 +STEER2SRV_P,1.8 +STEER2SRV_TCONST,0.75 +STICK_MIXING,1 +SYSID_ENFORCE,0 +SYSID_MYGCS,255 +SYSID_THISMAV,1 +TECS_APPR_SMAX,0 +TECS_CLMB_MAX,5 +TECS_FLARE_HGT,1 +TECS_HDEM_TCONST,3 +TECS_HGT_OMEGA,3 +TECS_INTEG_GAIN,0.3 +TECS_LAND_ARSPD,-1 +TECS_LAND_DAMP,0.5 +TECS_LAND_IGAIN,0 +TECS_LAND_PDAMP,0 +TECS_LAND_PMAX,10 +TECS_LAND_SINK,0.25 +TECS_LAND_SPDWGT,-1 +TECS_LAND_SRC,0 +TECS_LAND_TCONST,2 +TECS_LAND_TDAMP,0 +TECS_LAND_THR,-1 +TECS_OPTIONS,0 +TECS_PITCH_MAX,15 +TECS_PITCH_MIN,0 +TECS_PTCH_DAMP,0.3 +TECS_PTCH_FF_K,0 +TECS_PTCH_FF_V0,12 +TECS_RLL2THR,10 +TECS_SINK_MAX,5 +TECS_SINK_MIN,2 +TECS_SPD_OMEGA,2 +TECS_SPDWEIGHT,1 +TECS_SYNAIRSPEED,0 +TECS_THR_DAMP,0.5 +TECS_TIME_CONST,5 +TECS_TKOFF_IGAIN,0 +TECS_VERT_ACC,7 +TELEM_DELAY,0 +TERRAIN_CACHE_SZ,12 +TERRAIN_ENABLE,1 +TERRAIN_FOLLOW,0 +TERRAIN_LOOKAHD,2000 +TERRAIN_MARGIN,0.05 +TERRAIN_OFS_MAX,30 +TERRAIN_OPTIONS,0 +TERRAIN_SPACING,100 +THR_FAILSAFE,1 +THR_FS_VALUE,950 +THR_MAX,100 +THR_MIN,0 +THR_PASS_STAB,0 +THR_SLEWRATE,100 +THR_SUPP_MAN,0 +THROTTLE_NUDGE,1 +TKOFF_ACCEL_CNT,1 +TKOFF_ALT,50 +TKOFF_DIST,200 +TKOFF_FLAP_PCNT,0 +TKOFF_GND_PITCH,5 +TKOFF_LVL_ALT,10 +TKOFF_LVL_PITCH,15 +TKOFF_OPTIONS,0 +TKOFF_PLIM_SEC,2 +TKOFF_ROTATE_SPD,0 +TKOFF_TDRAG_ELEV,0 +TKOFF_TDRAG_SPD1,0 +TKOFF_THR_DELAY,2 +TKOFF_THR_MAX,0 +TKOFF_THR_MAX_T,4 +TKOFF_THR_MIN,0 +TKOFF_THR_MINACC,0 +TKOFF_THR_MINSPD,0 +TKOFF_THR_SLEW,0 +TKOFF_TIMEOUT,0 +TRIM_THROTTLE,45 +TUNE_CHAN,0 +TUNE_CHAN_MAX,2000 +TUNE_CHAN_MIN,1000 +TUNE_ERR_THRESH,0.15 +TUNE_MODE_REVERT,1 +TUNE_PARAM,0 +TUNE_RANGE,2 +TUNE_SELECTOR,0 +USE_REV_THRUST,2 +VISO_TYPE,0 +VTX_BAND,0 +VTX_CHANNEL,0 +VTX_ENABLE,1 +VTX_FREQ,0 +VTX_MAX_POWER,2500 +VTX_MODEL,0 +VTX_OPTIONS,0 +VTX_POW_CMW1,0 +VTX_POW_CMW2,0 +VTX_POW_CMW3,0 +VTX_POW_CMW4,0 +VTX_POW_CMW5,0 +VTX_POW_CMW6,0 +VTX_POW_CVAL1,0 +VTX_POW_CVAL2,1 +VTX_POW_CVAL3,2 +VTX_POW_CVAL4,3 +VTX_POW_CVAL5,4 +VTX_POW_CVAL6,5 +VTX_POW_LEVELS,6 +VTX_POWER,0 +VTX_PRESET1,0 +VTX_PRESET2,1 +VTX_PRESET3,2 +VTX_PRESET4,3 +VTX_PRESET5,4 +VTX_PRESET6,5 +WP_LOITER_RAD,60 +WP_MAX_RADIUS,0 +WP_RADIUS,90 +YAW_RATE_ENABLE,0 +YAW2SRV_DAMP,0 +YAW2SRV_IMAX,1500 +YAW2SRV_INT,0 +YAW2SRV_RLL,1 +YAW2SRV_SLIP,0 diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 0dea489..0fcee6f 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -434,12 +434,56 @@ def test_unknown_protocol(self, tmp_path): assert str(exc_info.value) == "Could not recognize log protocol." +class TestArdupilotMissionPlannerParamReaders: + """Test the MissionPlanner and more modern Ardupilot parameter file decoders.""" + + def test_mavproxy(self): + """Test reading from a parameter file saved by MAVProxy.""" + parameter_list = _helpers.read_params(utils.ARDUPILOT_DEFAULT_PARAM) + assert parameter_list["ARMING_ACCTHRESH"].value == pytest.approx(0.75) + + def test_split_row(self): + """Test that a number as the first element throws an error.""" + row = "42,42 # Comment" + with pytest.raises(SyntaxError) as exc_info: + _helpers.split_missionplanner_row(row) + assert ( + str(exc_info.value) == "MP: First row element must be a parameter name string." + ) + + def test_split_row_2(self): + """Ensure all 3 elements are decoded.""" + row = "NAME, 42 # Batman" + result = _helpers.split_missionplanner_row(row) + expected = ("NAME", "42", "Batman") + assert all([a == b for a, b in zip(result, expected)]) # noqa: B905 + # Disabling qa because 'strict' keyword not supported before 3.10 + + def test_parse_failure(self): + """Ensure an exception is thrown if parsing fails.""" + with pytest.raises(SyntaxError) as exc_info: + _helpers.read_params_missionplanner(utils.PX4_GAZEBO_PARAMS) + assert "File is not of MissionPlanner format" in str(exc_info.value) + + + def test_cyrillic_content(self): + """Ensure that value types 2,4,6,9 are correctly read.""" + parameter_list = _helpers.read_params(utils.ARDUPILOT_MP_PARAM) + assert parameter_list["AHRS_OPTIONS"].value == 3 + assert parameter_list["AHRS_OPTIONS"].reasoning == "відключить DCM fallback in VTOL and FW" + assert parameter_list["AHRS_GPS_USE"].value == 1 + assert parameter_list["AHRS_ORIG_LAT"].value == pytest.approx(37.09066) + + assert "ACRO_YAW_RATE" not in parameter_list + assert "AHRS_ORIG_ALT" not in parameter_list + + class TestArdupilotParamReaders: """Test the various Ardupilot parameter file decoders.""" def test_mavproxy(self): """Test reading from a parameter file saved by MAVProxy.""" - parameter_list = _helpers.read_params(utils.ARDUPILOT_DEFAULT_PARAMS) + parameter_list = _helpers.read_params(utils.ARDUPILOT_DEFAULT_PARM) assert parameter_list["ARMING_ACCTHRESH"].value == pytest.approx(0.75) def test_mavproxy_empty(self, tmp_path): @@ -482,7 +526,7 @@ def test_parse_failure(self): def test_qgc_rare_types(self): """Ensure that value types 2,4,6,9 are correctly read.""" - parameter_list = _helpers.read_params(utils.ARDUPILOT_ODD_PARAM_VALUES_FILE) + parameter_list = _helpers.read_params(utils.ARDUPILOT_ODD_PARAMS_VALUES_FILE) assert parameter_list["ACRO_TRAINER"].value == 2 assert parameter_list["ANGLE_MAX"].value == 3000 assert parameter_list["ARMING_CHECK"].value == 8214 diff --git a/tests/utils.py b/tests/utils.py index 8e9e56b..cce128d 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -20,10 +20,12 @@ PX4_INPUT_FOLDER = Path(PX4_ASSETS_PATH) / "menu" PX4_ULOG_PARAMS_FILE = PX4_ASSETS_PATH / "6fcfa754-186b-41ae-90a4-8de386f712c3.params" -PX4_ASSETS_PATH = Path(path.dirname(path.abspath(__file__))) / "assets" / "ardupilot" -ARDUPILOT_INPUT_FOLDER = Path(PX4_ASSETS_PATH) / "menu" -ARDUPILOT_DEFAULT_PARAMS = Path(PX4_ASSETS_PATH) / "sitl_copter_defaults.parm" -ARDUPILOT_ODD_PARAM_VALUES_FILE = Path(PX4_ASSETS_PATH) / "black_20231221.params" +ARDUPILOT_ASSETS_PATH = Path(path.dirname(path.abspath(__file__))) / "assets" / "ardupilot" +ARDUPILOT_INPUT_FOLDER = Path(ARDUPILOT_ASSETS_PATH) / "menu" +ARDUPILOT_DEFAULT_PARM = Path(ARDUPILOT_ASSETS_PATH) / "sitl_copter_defaults.parm" +ARDUPILOT_DEFAULT_PARAM = Path(ARDUPILOT_ASSETS_PATH) / "sitl_plane_defaults.param" +ARDUPILOT_MP_PARAM = Path(ARDUPILOT_ASSETS_PATH) / "mission_planner.param" +ARDUPILOT_ODD_PARAMS_VALUES_FILE = Path(ARDUPILOT_ASSETS_PATH) / "black_20231221.params" @pytest.fixture(name="setup_generic") @@ -59,7 +61,7 @@ def fixture_setup_px4(): def fixture_setup_ardupilot(): """Set up the parasect paths for Ardupilot testing.""" os.environ["PARASECT_PATH"] = str(ARDUPILOT_INPUT_FOLDER) - os.environ["PARASECT_DEFAULTS"] = str(ARDUPILOT_DEFAULT_PARAMS) + os.environ["PARASECT_DEFAULTS"] = str(ARDUPILOT_DEFAULT_PARM) parasect._helpers.ConfigPaths().clear()