diff --git a/docs/MixerProfile.md b/docs/MixerProfile.md index f6688feaeec..052298e73f5 100644 --- a/docs/MixerProfile.md +++ b/docs/MixerProfile.md @@ -133,6 +133,9 @@ save When `mixer_automated_switch`:`OFF` is set for all mixer_profiles(defaults). Model will not perform automated transition at all. +### TailSitter support +TailSitter is supported by add a 90deg offset to the board alignment. Set the board aliment normally in the mixer_profile for FW mode(`set platform_type = AIRPLANE`), The motor trust axis should be same direction as the airplane nose. Then, in the mixer_profile for takeoff and landing `set platform_type = TAILSITTER`. The `TAILSITTER` platform type is same as `MULTIROTOR` platform type, expect for a 90 deg board alignment offset. In `TAILSITTER` mixer_profile, when motor trust/airplane nose is pointing to the sky, 'airplane bottom'/'multi rotor front' should facing forward in model preview. Set the motor/servo mixer according to multirotor orientation, Model should roll around geography's longitudinal axis, the roll axis of `TAILSITTER` will be yaw axis of `AIRPLANE`. In addition, When `MIXER TRANSITION` input is activated, a 45deg offset will be add to the target angle for angle mode. + ## Happy flying Remember that this is currently an emerging capability: diff --git a/docs/Screenshots/mixerprofile_4puls1_mix.png b/docs/Screenshots/mixerprofile_4puls1_mix.png new file mode 100644 index 00000000000..9fdae07077a Binary files /dev/null and b/docs/Screenshots/mixerprofile_4puls1_mix.png differ diff --git a/docs/Screenshots/mixerprofile_flow.png b/docs/Screenshots/mixerprofile_flow.png new file mode 100644 index 00000000000..292949b23b7 Binary files /dev/null and b/docs/Screenshots/mixerprofile_flow.png differ diff --git a/docs/Screenshots/mixerprofile_fw_mixer.png b/docs/Screenshots/mixerprofile_fw_mixer.png new file mode 100644 index 00000000000..b27b1b4b78a Binary files /dev/null and b/docs/Screenshots/mixerprofile_fw_mixer.png differ diff --git a/docs/Screenshots/mixerprofile_mc_mixer.png b/docs/Screenshots/mixerprofile_mc_mixer.png new file mode 100644 index 00000000000..fe1766665ae Binary files /dev/null and b/docs/Screenshots/mixerprofile_mc_mixer.png differ diff --git a/docs/Screenshots/mixerprofile_servo_transition_mix.png b/docs/Screenshots/mixerprofile_servo_transition_mix.png new file mode 100644 index 00000000000..31e40ff5480 Binary files /dev/null and b/docs/Screenshots/mixerprofile_servo_transition_mix.png differ diff --git a/docs/Settings.md b/docs/Settings.md index 4f6db8c8b3c..f1868198d46 100644 --- a/docs/Settings.md +++ b/docs/Settings.md @@ -1222,16 +1222,6 @@ Iterm is not allowed to grow when stick position is above threshold. This solves --- -### fw_iterm_throw_limit - -Limits max/min I-term value in stabilization PID controller in case of Fixed Wing. It solves the problem of servo saturation before take-off/throwing the airplane into the air. By default, error accumulated in I-term can not exceed 1/3 of servo throw (around 165us). Set 0 to disable completely. - -| Default | Min | Max | -| --- | --- | --- | -| 165 | FW_ITERM_THROW_LIMIT_MIN | FW_ITERM_THROW_LIMIT_MAX | - ---- - ### fw_level_pitch_gain I-gain for the pitch trim for self-leveling flight modes. Higher values means that AUTOTRIM will be faster but might introduce oscillations @@ -1924,7 +1914,7 @@ Calculated 1G of Acc axis Z to use in INS ### iterm_windup -Used to prevent Iterm accumulation on during maneuvers. Iterm will be dampened when motors are reaching it's limit (when requested motor correction range is above percentage specified by this parameter) +Used to prevent Iterm accumulation on during maneuvers. Iterm accumulation will be dampened when motors are reaching it's limit (when requested motor correction range is close percentage specified by this parameter, when value is set below 50 no accumulation occors when iterm_windup+50 of motor correction range is reached) | Default | Min | Max | | --- | --- | --- | @@ -4802,6 +4792,16 @@ Video system used. Possible values are `AUTO`, `PAL`, `NTSC`, `HDZERO`, 'DJIWTF' --- +### pid_iterm_limit_percent + +Limits max/min I-term value in stabilization PID controller. It solves the problem of servo saturation before take-off/throwing the airplane into the air. Or multirotors with low authority. By default, error accumulated in I-term can not exceed 33% of total pid throw (around 165us on deafult pidsum_limit of pitch/roll). Set 0 to disable completely. + +| Default | Min | Max | +| --- | --- | --- | +| 33 | 0 | 200 | + +--- + ### pid_type Allows to set type of PID controller used in control loop. Possible values: `NONE`, `PID`, `PIFF`, `AUTO`. Change only in case of experimental platforms like VTOL, tailsitters, rovers, boats, etc. Airplanes should always use `PIFF` and multirotors `PID` @@ -5602,6 +5602,16 @@ Delay before disarming when requested by switch (ms) [0-1000] --- +### tailsitter_orientation_offset + +Apply a 90 deg pitch offset in sensor aliment for tailsitter flying mode + +| Default | Min | Max | +| --- | --- | --- | +| OFF | OFF | ON | + +--- + ### telemetry_halfduplex S.Port telemetry only: Turn UART into UNIDIR for usage on F1 and F4 target. See Telemetry.md for details @@ -5702,9 +5712,19 @@ See tpa_rate. --- +### tpa_on_yaw + +Throttle PID attenuation also reduces influence on YAW for multi-rotor, Should be set to ON for tilting rotors. + +| Default | Min | Max | +| --- | --- | --- | +| OFF | OFF | ON | + +--- + ### tpa_rate -Throttle PID attenuation reduces influence of P on ROLL and PITCH as throttle increases. For every 1% throttle after the TPA breakpoint, P is reduced by the TPA rate. +Throttle PID attenuation reduces influence of PDFF on ROLL and PITCH of multi-rotor, PIDFF on ROLL,PITCH,YAW OF fixed_wing as throttle increases. For every 1% throttle after the TPA breakpoint, P is reduced by the TPA rate. | Default | Min | Max | | --- | --- | --- | diff --git a/docs/VTOL.md b/docs/VTOL.md new file mode 100644 index 00000000000..0990a03e3b2 --- /dev/null +++ b/docs/VTOL.md @@ -0,0 +1,206 @@ +# Welcome to INAV VTOL Testing + +Thank you for participating in the INAV VTOL testing phase. + +## Who Should Use This Tutorial? + +This tutorial is designed for individuals who have prior experience with **both INAV multi-rotor and INAV fixed-wing configurations/operations.** If you're not familiar with them, this tutorial might be not for you. + +## Firmware Status + +The firmware is in a flyable state, but it hasn't undergone extensive testing yet. This means there may be potential issues that have not yet been discovered. + +## Future Changes + +Please be aware that both the setup procedure and firmware may change in response to user feedback and testing results. +## Your Feedback Matters + +We highly value your feedback as it plays a crucial role in the development and refinement of INAV VTOL capabilities. Please share your experiences, suggestions, and any issues you encounter during testing. Your insights are invaluable in making INAV VTOL better for everyone. + +# VTOL Configuration Steps + +### The VTOL functionality is achieved by switching/transitioning between two configurations stored in the FC. VTOL specific configurations are Mixer Profiles with associated PID profiles. One profile set is for fixed-wing(FW) mode, One is for multi-copter(MC) mode. Configuration/Settings other than Mixer/PID profiles are shared among two modes +![Alt text](Screenshots/mixerprofile_flow.png) + +0. **Find a DIFF ALL file for your model and start from there if possible** + - Be aware that `MIXER PROFILE 2` RC mode setting introduced by diff file can get your stuck in a mixer_profile. remove or change channel to proceed +1. **Setup Profile 1:** + - Configure it as a normal fixed-wing/multi-copter. + +2. **Setup Profile 2:** + - Configure it as a normal multi-copter/fixed-wing. + +3. **Mode Tab Settings:** + - Set up switching in the mode tab. + +4. *(Recommended)* **Transition Mixing (Multi-Rotor Profile):** + - Configure transition mixing to gain airspeed in the multi-rotor profile. + +5. *(Recommended)* **VTOL-Specific Settings:** + - Configure VTOL-specific settings. + +6. *(Optional)* **Automated Switching (RTH):** + - Optionally, set up automated switching in case of failsafe. + +# STEP1&2: Configuring as a Normal fixed-wing/Multi-Copter in two profiles separately + +1. **Select the fisrt Mixer Profile and PID Profile:** + - In the CLI, switch to the mixer_profile and pid_profile you wish to set first: + ``` + mixer_profile 1 #in this example, we set profile 1 first + set mixer_pid_profile_linking = ON # Let the mixer_profile handle the pid_profile switch on this mixer_profile + set platform_type = AIRPLANE + save + ``` + +2. **Configure the fixed-wing/Multi-Copter:** + - Configure your fixed-wing/Multi-Copter as you normally would, or you can copy and paste default settings to expedite the process. + - Dshot esc protocol availability might be limited depends on outputs and fc board you are using. change the motor wiring or use oneshot/multishot esc protocol and calibrate throttle range. + - You can use throttle = -1 as a placeholder for the motor you wish to stop if the motor isn't the last motor + - Consider conducting a test flight to ensure that everything operates as expected. And tune the settings, trim the servos. + +![Alt text](Screenshots/mixerprofile_fw_mixer.png) + +3. **Switch to Another Mixer Profile with PID Profile:** + - In the CLI, switch to another mixer_profile along with the appropriate pid_profile: + ``` + mixer_profile 2 + set mixer_pid_profile_linking = ON + set platform_type = MULTIROTOR + save + ``` + +4. **Configure the Multi-Copter/fixed-wing:** + - Set up your multi-copter/fixed-wing as usual, this time for mixer_profile 2 and pid_profile 2. + - Utilize the 'MAX' input in the servo mixer to tilt the motors without altering the servo midpoint. + - At this stage, focus on configuring profile-specific settings. You can streamline this process by copying and pasting the default PID settings. + - compass is required to enable navigation modes for multi-rotor profile. + - Consider conducting a test flight to ensure that everything operates as expected. And tune the settings. + - It is advisable to have a certain degree of control surface (elevon / elevator) mapping for stabilization even in multi-copter mode. This helps improve control authority when airspeed is high. + +![Alt text](Screenshots/mixerprofile_mc_mixer.png) + +5. **Tailsitters:** +Working in progress. + - Configure the fixed-wing mode/profile sets normally. Use MultiCopter platform type for tail_sitting flying mode/profile sets. + - The baseline board aliment is FW mode(ROLL axis is the trust axis). So set `tailsitter_orientation_offset = ON ` in the tail_sitting MC mode. + - Configure mixer ROLL/YAW mixing according to tail_sitting orientation in the tail_sitting MC mode. YAW axis is the trust axis. + - Conduct a bench test and see the orientation of the model changes in inav-configurator setup tab + +# STEP3: Mode Tab Settings: +### We recommend using an 3-pos switch on you radio to activate these modes, So pilot can jump in or bell out at any moment. +### Here is a example, in the bottom of inav-configurator Modes tab: +![Alt text](Screenshots/mixer_profile.png) +| 1000~1300 | 1300~1700 | 1700~2000 | +| :-- | :-- | :-- | +| Profile1(FW) with transition off | Profile2(MC) with transition on | Profile2(MC) with transition off | + +- Profile file switching becomes available after completing the runtime sensor calibration(15-30s after booting). And It is **not available** when a navigation mode or position hold is active. + +- By default, `mixer_profile 1` is used. `mixer_profile 2` is used when the `MIXER PROFILE 2` mode is activate. Once configured successfully, you will notice that the profiles and model preview changes accordingly when you refresh the relevant INAV Configurator tabs. + +- Use the `MIXER TRANSITION` mode to gain airspeed in MC profile, set `MIXER TRANSITION` accordingly. + +Conduct a bench test on the model (without props attached). The model can now switch between fixed-wing and multi-copter modes while armed. Furthermore, it is capable of mid-air switching, resulting in an immediate stall upon entering fixed-wing profile + +# STEP4: Transition Mixing (Multi-Rotor Profile)(Recommended) +### Transition Mixing is typically useful in multi-copter profile to gain airspeed in prior to entering the fixed-wing profile. When the `MIXER TRANSITION` mode is activated, the associated motor or servo will move according to your configured Transition Mixing. + +Please note that transition input is disabled when a navigation mode is activated. The use of Transition Mixing is necessary to enable additional features such as VTOL RTH with out stalling. +## Servo 'Transition Mixing': Tilting rotor configuration. +Add new servo mixer rules, and select 'Mixer Transition' in input. Set the weight/rate according to your desired angle. This will allow tilting the motor for tilting rotor model. + +![Alt text](Screenshots/mixerprofile_servo_transition_mix.png) + +## Motor 'Transition Mixing': Dedicated forward motor configuration +In motor mixer set: +- -2.0 < throttle < -1.0: The motor will spin regardless of the radio's throttle position at a speed of `abs(throttle) - 1` multiplied by throttle range only when Mixer Transition is activated. + +![Alt text](Screenshots/mixerprofile_4puls1_mix.png) + +## TailSitter 'Transition Mixing': +No additional settings needed, 45deg off set will be added to target pitch angle for angle mode in the firmware. + +### With aforementioned settings, your model should be able to enter fixed-wing profile without stalling. + +# STEP5: VTOL-Specific Settings (Recommended): +### recommended settings, more based on field experience are coming +``` +set nav_disarm_on_landing = OFF #band-aid for false landing detection in NAV landing of multi-copter +set airmode_type = STICK_CENTER_ONCE +set ahrs_inertia_comp_method = ADAPTIVE # will automatically use VELNED in mc mode +set tpa_on_yaw = ON #For yaw control by tilt rotor in the MC pid_profile +set servo_pwm_rate = 160 #For yaw control by tilt rotor model +set servo_lpf_hz = 30 #For yaw control by tilt rotor model +``` + +# Automated Switching (RTH) (Optional): +### This is one of the least tested features. This feature is primarily designed for Return to Home (RTH) in the event of a failsafe. +When configured correctly, the model will use the Fixed-Wing (FW) mode to efficiently return home and then transition to Multi-Copter (MC) mode for easier landing. + +To enable this feature, type follwoing command in cli + +1. In your MC mode mixer profile (e.g., mixer_profile 2), set `mixer_automated_switch` to `ON`. leave it to `OFF` if burning remaining battery capacity on the way home is acceptable. +``` +mixer_profile 2or1 +set mixer_automated_switch= ON +``` + +2. Set `mixer_switch_trans_timer` ds in cli in the MC mode mixer profile to specify the time required for your model to gain sufficient airspeed before transitioning to FW mode. +``` +mixer_profile 2or1 +set mixer_switch_trans_timer = 30 # 3s, 3000ms +``` +3. In your FW mode mixer profile (e.g., mixer_profile 1), also set `mixer_automated_switch` to `ON`. leave it to `OFF` if automated landing in fixed-wing is acceptable. +``` +mixer_profile 1or2 +set mixer_automated_switch = ON +``` +4. Save your settings. type `save` in cli. + +If you set `mixer_automated_switch` to `OFF` for all mixer profiles (the default setting), the model will not perform automated transitions. You can always enable navigation modes after performing a manual transition. + + +# Notes and Experiences +## General +- VTOL model operating in multi-copter (MC) mode may encounter challenges in windy conditions. Please exercise caution when testing in such conditions. + +## Tilting-rotor +- In some tilting motor models, you may experience roll/yaw coupled oscillations when `MIXER TRANSITION` is activated. To address this issue, you can try the following: + 1. try hard on pid + 1. try different prop direction, prop size. + 2. you can add servo mixing rules to decouple the control input. such use tilt servo for roll control + 3. Use a logic condition to ensure that these compensation servo mixing rules are active only when `MIXER TRANSITION` is activated. You can achieve this by checking the value of 'Flight:MixerTransition Active' in programming tab. + 4. Add a little roll mixing in tilt motors. +## Dedicated forward motor +- waiting for reports + +# Parameter list (Partial List) +### Please be aware of what parameter is shared among FW/MC modes and what isn't. +## Shared Parameters + +- **Timer Overrides** +- **Outputs [Servo]:** + - Servo min-point, mid-point, max-point settings +- **Motor Configuration:** + - motor_pwm_protocol + - motor_poles +- **Servo Configuration:** + - servo_protocol + - servo_pwm_rate +- **Board Alignment** +- ······· +## Profile-Specific Parameters in VTOL +- **Mixer Profile** + - **Mixer Configuration:** + - platform_type + - motor_stop_on_low + - motor_direction_inverted, and more······· + - **Motor Mixing (mmix)** + - **Servo Mixing (smix)** +- **PID Profile** + - PIDs for Roll, Pitch, Yaw + - PIDs for Navigation Modes + - TPA (Throttle PID Attenuation) Settings + - Rate Settings + - ······· \ No newline at end of file diff --git a/src/main/common/maths.h b/src/main/common/maths.h index ff0505fb531..1daed3ef6aa 100644 --- a/src/main/common/maths.h +++ b/src/main/common/maths.h @@ -91,6 +91,7 @@ ) #define MIN(a, b) _CHOOSE(<, a, b) #define MAX(a, b) _CHOOSE(>, a, b) +#define SIGN(a) ((a >= 0) ? 1 : -1) #define _ABS_II(x, var) \ ( __extension__ ({ \ diff --git a/src/main/fc/controlrate_profile.c b/src/main/fc/controlrate_profile.c index 18f5bd343b6..c8b144e136c 100644 --- a/src/main/fc/controlrate_profile.c +++ b/src/main/fc/controlrate_profile.c @@ -44,6 +44,7 @@ void pgResetFn_controlRateProfiles(controlRateConfig_t *instance) .rcMid8 = SETTING_THR_MID_DEFAULT, .rcExpo8 = SETTING_THR_EXPO_DEFAULT, .dynPID = SETTING_TPA_RATE_DEFAULT, + .dynPID_on_YAW = SETTING_TPA_ON_YAW_DEFAULT, .pa_breakpoint = SETTING_TPA_BREAKPOINT_DEFAULT, .fixedWingTauMs = SETTING_FW_TPA_TIME_CONSTANT_DEFAULT }, diff --git a/src/main/fc/controlrate_profile_config_struct.h b/src/main/fc/controlrate_profile_config_struct.h index e07c328560c..e4038537603 100644 --- a/src/main/fc/controlrate_profile_config_struct.h +++ b/src/main/fc/controlrate_profile_config_struct.h @@ -29,6 +29,7 @@ typedef struct controlRateConfig_s { uint8_t rcMid8; uint8_t rcExpo8; uint8_t dynPID; + bool dynPID_on_YAW; uint16_t pa_breakpoint; // Breakpoint where TPA is activated uint16_t fixedWingTauMs; // Time constant of airplane TPA PT1-filter } throttle; diff --git a/src/main/fc/fc_msp.c b/src/main/fc/fc_msp.c index 0f3d80829ab..4e0c102d330 100644 --- a/src/main/fc/fc_msp.c +++ b/src/main/fc/fc_msp.c @@ -461,6 +461,7 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF sbufWriteU16(dst, packSensorStatus()); sbufWriteU16(dst, averageSystemLoadPercent); sbufWriteU8(dst, (getConfigBatteryProfile() << 4) | getConfigProfile()); + sbufWriteU8(dst, getConfigMixerProfile()); sbufWriteU32(dst, armingFlags); sbufWriteData(dst, &mspBoxModeFlags, sizeof(mspBoxModeFlags)); } @@ -522,6 +523,18 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF sbufWriteU8(dst, -1); #endif } + if(MAX_MIXER_PROFILE_COUNT==1) break; + for (int i = 0; i < MAX_SERVO_RULES; i++) { + sbufWriteU8(dst, mixerServoMixersByIndex(nextMixerProfileIndex)[i].targetChannel); + sbufWriteU8(dst, mixerServoMixersByIndex(nextMixerProfileIndex)[i].inputSource); + sbufWriteU16(dst, mixerServoMixersByIndex(nextMixerProfileIndex)[i].rate); + sbufWriteU8(dst, mixerServoMixersByIndex(nextMixerProfileIndex)[i].speed); + #ifdef USE_PROGRAMMING_FRAMEWORK + sbufWriteU8(dst, mixerServoMixersByIndex(nextMixerProfileIndex)[i].conditionId); + #else + sbufWriteU8(dst, -1); + #endif + } break; #ifdef USE_PROGRAMMING_FRAMEWORK case MSP2_INAV_LOGIC_CONDITIONS: @@ -567,11 +580,18 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF #endif case MSP2_COMMON_MOTOR_MIXER: for (uint8_t i = 0; i < MAX_SUPPORTED_MOTORS; i++) { - sbufWriteU16(dst, primaryMotorMixer(i)->throttle * 1000); + sbufWriteU16(dst, constrainf(primaryMotorMixer(i)->throttle + 2.0f, 0.0f, 4.0f) * 1000); sbufWriteU16(dst, constrainf(primaryMotorMixer(i)->roll + 2.0f, 0.0f, 4.0f) * 1000); sbufWriteU16(dst, constrainf(primaryMotorMixer(i)->pitch + 2.0f, 0.0f, 4.0f) * 1000); sbufWriteU16(dst, constrainf(primaryMotorMixer(i)->yaw + 2.0f, 0.0f, 4.0f) * 1000); } + if (MAX_MIXER_PROFILE_COUNT==1) break; + for (uint8_t i = 0; i < MAX_SUPPORTED_MOTORS; i++) { + sbufWriteU16(dst, constrainf(mixerMotorMixersByIndex(nextMixerProfileIndex)[i].throttle + 2.0f, 0.0f, 4.0f) * 1000); + sbufWriteU16(dst, constrainf(mixerMotorMixersByIndex(nextMixerProfileIndex)[i].roll + 2.0f, 0.0f, 4.0f) * 1000); + sbufWriteU16(dst, constrainf(mixerMotorMixersByIndex(nextMixerProfileIndex)[i].pitch + 2.0f, 0.0f, 4.0f) * 1000); + sbufWriteU16(dst, constrainf(mixerMotorMixersByIndex(nextMixerProfileIndex)[i].yaw + 2.0f, 0.0f, 4.0f) * 1000); + } break; case MSP_MOTOR: @@ -2100,7 +2120,7 @@ static mspResult_e mspFcProcessInCommand(uint16_t cmdMSP, sbuf_t *src) case MSP2_COMMON_SET_MOTOR_MIXER: sbufReadU8Safe(&tmp_u8, src); if ((dataSize == 9) && (tmp_u8 < MAX_SUPPORTED_MOTORS)) { - primaryMotorMixerMutable(tmp_u8)->throttle = constrainf(sbufReadU16(src) / 1000.0f, 0.0f, 1.0f); + primaryMotorMixerMutable(tmp_u8)->throttle = constrainf(sbufReadU16(src) / 1000.0f, 0.0f, 4.0f) - 2.0f; primaryMotorMixerMutable(tmp_u8)->roll = constrainf(sbufReadU16(src) / 1000.0f, 0.0f, 4.0f) - 2.0f; primaryMotorMixerMutable(tmp_u8)->pitch = constrainf(sbufReadU16(src) / 1000.0f, 0.0f, 4.0f) - 2.0f; primaryMotorMixerMutable(tmp_u8)->yaw = constrainf(sbufReadU16(src) / 1000.0f, 0.0f, 4.0f) - 2.0f; @@ -2994,6 +3014,14 @@ static mspResult_e mspFcProcessInCommand(uint16_t cmdMSP, sbuf_t *src) } break; + case MSP2_INAV_SELECT_MIXER_PROFILE: + if (!ARMING_FLAG(ARMED) && sbufReadU8Safe(&tmp_u8, src)) { + setConfigMixerProfileAndWriteEEPROM(tmp_u8); + } else { + return MSP_RESULT_ERROR; + } + break; + #ifdef USE_TEMPERATURE_SENSOR case MSP2_INAV_SET_TEMP_SENSOR_CONFIG: if (dataSize == sizeof(tempSensorConfig_t) * MAX_TEMP_SENSORS) { diff --git a/src/main/fc/runtime_config.h b/src/main/fc/runtime_config.h index 16d1b411df8..94eb23bd6a6 100644 --- a/src/main/fc/runtime_config.h +++ b/src/main/fc/runtime_config.h @@ -139,6 +139,7 @@ typedef enum { FW_HEADING_USE_YAW = (1 << 24), ANTI_WINDUP_DEACTIVATED = (1 << 25), LANDING_DETECTED = (1 << 26), + TAILSITTER = (1 << 27), //offset the pitch angle by 90 degrees } stateFlags_t; #define DISABLE_STATE(mask) (stateFlags &= ~(mask)) diff --git a/src/main/fc/settings.yaml b/src/main/fc/settings.yaml index 06b2213890a..e4462ebe4a3 100755 --- a/src/main/fc/settings.yaml +++ b/src/main/fc/settings.yaml @@ -1182,6 +1182,11 @@ groups: field: mixer_config.switchTransitionTimer min: 0 max: 200 + - name: tailsitter_orientation_offset + description: "Apply a 90 deg pitch offset in sensor aliment for tailsitter flying mode" + default_value: OFF + field: mixer_config.tailsitterOrientationOffset + type: bool @@ -1267,7 +1272,7 @@ groups: min: 0 max: 100 - name: tpa_rate - description: "Throttle PID attenuation reduces influence of P on ROLL and PITCH as throttle increases. For every 1% throttle after the TPA breakpoint, P is reduced by the TPA rate." + description: "Throttle PID attenuation reduces influence of PDFF on ROLL and PITCH of multi-rotor, PIDFF on ROLL,PITCH,YAW OF fixed_wing as throttle increases. For every 1% throttle after the TPA breakpoint, P is reduced by the TPA rate." default_value: 0 field: throttle.dynPID min: 0 @@ -1278,6 +1283,11 @@ groups: field: throttle.pa_breakpoint min: PWM_RANGE_MIN max: PWM_RANGE_MAX + - name: tpa_on_yaw + description: "Throttle PID attenuation also reduces influence on YAW for multi-rotor, Should be set to ON for tilting rotors." + type: bool + field: throttle.dynPID_on_YAW + default_value: OFF - name: fw_tpa_time_constant description: "TPA smoothing and delay time constant to reflect non-instant speed/throttle response of the plane. See **PID Attenuation and scaling** Wiki for full details." default_value: 1500 @@ -1851,12 +1861,6 @@ groups: default_value: 0 min: 0 max: 200 - - name: fw_iterm_throw_limit - description: "Limits max/min I-term value in stabilization PID controller in case of Fixed Wing. It solves the problem of servo saturation before take-off/throwing the airplane into the air. By default, error accumulated in I-term can not exceed 1/3 of servo throw (around 165us). Set 0 to disable completely." - default_value: 165 - field: fixedWingItermThrowLimit - min: FW_ITERM_THROW_LIMIT_MIN - max: FW_ITERM_THROW_LIMIT_MAX - name: fw_reference_airspeed description: "Reference airspeed. Set this to airspeed at which PIDs were tuned. Usually should be set to cruise airspeed. Also used for coordinated turn calculation if airspeed sensor is not present." default_value: 1500 @@ -1900,11 +1904,17 @@ groups: min: PID_SUM_LIMIT_MIN max: PID_SUM_LIMIT_MAX - name: iterm_windup - description: "Used to prevent Iterm accumulation on during maneuvers. Iterm will be dampened when motors are reaching it's limit (when requested motor correction range is above percentage specified by this parameter)" + description: "Used to prevent Iterm accumulation on during maneuvers. Iterm accumulation will be dampened when motors are reaching it's limit (when requested motor correction range is close percentage specified by this parameter, when value is set below 50 no accumulation occors when iterm_windup+50 of motor correction range is reached)" default_value: 50 field: itermWindupPointPercent min: 0 max: 90 + - name: pid_iterm_limit_percent + description: "Limits max/min I-term value in stabilization PID controller. It solves the problem of servo saturation before take-off/throwing the airplane into the air. Or multirotors with low authority. By default, error accumulated in I-term can not exceed 33% of total pid throw (around 165us on deafult pidsum_limit of pitch/roll). Set 0 to disable completely." + default_value: 33 + field: pidItermLimitPercent + min: 0 + max: 200 - name: rate_accel_limit_roll_pitch description: "Limits acceleration of ROLL/PITCH rotation speed that can be requested by stick input. In degrees-per-second-squared. Small and powerful UAV flies great with high acceleration limit ( > 5000 dps^2 and even > 10000 dps^2). Big and heavy multirotors will benefit from low acceleration limit (~ 360 dps^2). When set correctly, it greatly improves stopping performance. Value of 0 disables limiting." default_value: 0 diff --git a/src/main/flight/imu.c b/src/main/flight/imu.c index ed5cbcbfaa4..585097b88a6 100644 --- a/src/main/flight/imu.c +++ b/src/main/flight/imu.c @@ -660,6 +660,33 @@ static void imuCalculateTurnRateacceleration(fpVector3_t *vEstcentrifugalAccelBF lastspeed = currentspeed; } +fpQuaternion_t* getTailSitterQuaternion(bool normal2tail){ + static bool firstRun = true; + static fpQuaternion_t qNormal2Tail; + static fpQuaternion_t qTail2Normal; + if(firstRun){ + fpAxisAngle_t axisAngle; + axisAngle.axis.x = 0; + axisAngle.axis.y = 1; + axisAngle.axis.z = 0; + axisAngle.angle = DEGREES_TO_RADIANS(-90); + axisAngleToQuaternion(&qNormal2Tail, &axisAngle); + quaternionConjugate(&qTail2Normal, &qNormal2Tail); + firstRun = false; + } + return normal2tail ? &qNormal2Tail : &qTail2Normal; +} + +void imuUpdateTailSitter(void) +{ + static bool lastTailSitter=false; + if (((bool)STATE(TAILSITTER)) != lastTailSitter){ + fpQuaternion_t* rotation_for_tailsitter= getTailSitterQuaternion(STATE(TAILSITTER)); + quaternionMultiply(&orientation, &orientation, rotation_for_tailsitter); + } + lastTailSitter = STATE(TAILSITTER); +} + static void imuCalculateEstimatedAttitude(float dT) { #if defined(USE_MAG) @@ -763,6 +790,7 @@ static void imuCalculateEstimatedAttitude(float dT) useCOG, courseOverGround, accWeight, magWeight); + imuUpdateTailSitter(); imuUpdateEulerAngles(); } diff --git a/src/main/flight/mixer.c b/src/main/flight/mixer.c index 35674c1f5dc..834841e6580 100644 --- a/src/main/flight/mixer.c +++ b/src/main/flight/mixer.c @@ -161,6 +161,7 @@ void mixerUpdateStateFlags(void) DISABLE_STATE(BOAT); DISABLE_STATE(AIRPLANE); DISABLE_STATE(MOVE_FORWARD_ONLY); + DISABLE_STATE(TAILSITTER); if (currentMixerConfig.platformType == PLATFORM_AIRPLANE) { ENABLE_STATE(FIXED_WING_LEGACY); @@ -186,6 +187,12 @@ void mixerUpdateStateFlags(void) ENABLE_STATE(ALTITUDE_CONTROL); } + if (currentMixerConfig.tailsitterOrientationOffset) { + ENABLE_STATE(TAILSITTER); + } else { + DISABLE_STATE(TAILSITTER); + } + if (currentMixerConfig.hasFlaps) { ENABLE_STATE(FLAPERON_AVAILABLE); } else { diff --git a/src/main/flight/mixer_profile.c b/src/main/flight/mixer_profile.c index 6f2b6b0920b..7b2590ff70b 100644 --- a/src/main/flight/mixer_profile.c +++ b/src/main/flight/mixer_profile.c @@ -35,7 +35,7 @@ int currentMixerProfileIndex; bool isMixerTransitionMixing; bool isMixerTransitionMixing_requested; mixerProfileAT_t mixerProfileAT; -int nextProfileIndex; +int nextMixerProfileIndex; PG_REGISTER_ARRAY_WITH_RESET_FN(mixerProfile_t, MAX_MIXER_PROFILE_COUNT, mixerProfiles, PG_MIXER_PROFILE, 1); @@ -53,6 +53,7 @@ void pgResetFn_mixerProfiles(mixerProfile_t *instance) .PIDProfileLinking = SETTING_MIXER_PID_PROFILE_LINKING_DEFAULT, .automated_switch = SETTING_MIXER_AUTOMATED_SWITCH_DEFAULT, .switchTransitionTimer = SETTING_MIXER_SWITCH_TRANS_TIMER_DEFAULT, + .tailsitterOrientationOffset = SETTING_TAILSITTER_ORIENTATION_OFFSET_DEFAULT, }); for (int j = 0; j < MAX_SUPPORTED_MOTORS; j++) { @@ -81,7 +82,7 @@ void pgResetFn_mixerProfiles(mixerProfile_t *instance) void activateMixerConfig(){ currentMixerProfileIndex = getConfigMixerProfile(); currentMixerConfig = *mixerConfig(); - nextProfileIndex = (currentMixerProfileIndex + 1) % MAX_MIXER_PROFILE_COUNT; + nextMixerProfileIndex = (currentMixerProfileIndex + 1) % MAX_MIXER_PROFILE_COUNT; } void mixerConfigInit(void) @@ -113,7 +114,7 @@ bool platformTypeConfigured(flyingPlatformType_e platformType) if (!isModeActivationConditionPresent(BOXMIXERPROFILE)){ return false; } - return mixerConfigByIndex(nextProfileIndex)->platformType == platformType; + return mixerConfigByIndex(nextMixerProfileIndex)->platformType == platformType; } bool checkMixerATRequired(mixerProfileATRequest_e required_action) @@ -171,7 +172,7 @@ bool mixerATUpdateState(mixerProfileATRequest_e required_action) isMixerTransitionMixing_requested = true; if (millis() > mixerProfileAT.transitionTransEndTime){ isMixerTransitionMixing_requested = false; - outputProfileHotSwitch(nextProfileIndex); + outputProfileHotSwitch(nextMixerProfileIndex); mixerProfileAT.phase = MIXERAT_PHASE_IDLE; reprocessState = true; //transition is done diff --git a/src/main/flight/mixer_profile.h b/src/main/flight/mixer_profile.h index d2208d7b8c0..947ca701553 100644 --- a/src/main/flight/mixer_profile.h +++ b/src/main/flight/mixer_profile.h @@ -18,6 +18,7 @@ typedef struct mixerConfig_s { bool PIDProfileLinking; bool automated_switch; int16_t switchTransitionTimer; + bool tailsitterOrientationOffset; } mixerConfig_t; typedef struct mixerProfile_s { mixerConfig_t mixer_config; @@ -54,6 +55,7 @@ bool mixerATUpdateState(mixerProfileATRequest_e required_action); extern mixerConfig_t currentMixerConfig; extern int currentMixerProfileIndex; +extern int nextMixerProfileIndex; extern bool isMixerTransitionMixing; #define mixerConfig() (&(mixerProfiles(systemConfig()->current_mixer_profile_index)->mixer_config)) #define mixerConfigMutable() ((mixerConfig_t *) mixerConfig()) diff --git a/src/main/flight/pid.c b/src/main/flight/pid.c index 3049fbb8224..fd29c748952 100644 --- a/src/main/flight/pid.c +++ b/src/main/flight/pid.c @@ -149,6 +149,7 @@ static EXTENDED_FASTRAM float dBoostMaxAtAlleceleration; static EXTENDED_FASTRAM uint8_t yawLpfHz; static EXTENDED_FASTRAM float motorItermWindupPoint; +static EXTENDED_FASTRAM float motorItermWindupPoint_inv; static EXTENDED_FASTRAM float antiWindupScaler; #ifdef USE_ANTIGRAVITY static EXTENDED_FASTRAM float iTermAntigravityGain; @@ -264,8 +265,8 @@ PG_RESET_TEMPLATE(pidProfile_t, pidProfile, .max_angle_inclination[FD_PITCH] = SETTING_MAX_ANGLE_INCLINATION_PIT_DEFAULT, .pidSumLimit = SETTING_PIDSUM_LIMIT_DEFAULT, .pidSumLimitYaw = SETTING_PIDSUM_LIMIT_YAW_DEFAULT, + .pidItermLimitPercent = SETTING_PID_ITERM_LIMIT_PERCENT_DEFAULT, - .fixedWingItermThrowLimit = SETTING_FW_ITERM_THROW_LIMIT_DEFAULT, .fixedWingReferenceAirspeed = SETTING_FW_REFERENCE_AIRSPEED_DEFAULT, .fixedWingCoordinatedYawGain = SETTING_FW_TURN_ASSIST_YAW_GAIN_DEFAULT, .fixedWingCoordinatedPitchGain = SETTING_FW_TURN_ASSIST_PITCH_GAIN_DEFAULT, @@ -531,7 +532,7 @@ void updatePIDCoefficients(void) pidState[axis].kT = 0.0f; } else { - const float axisTPA = (axis == FD_YAW) ? 1.0f : tpaFactor; + const float axisTPA = (axis == FD_YAW && (!currentControlRateProfile->throttle.dynPID_on_YAW)) ? 1.0f : tpaFactor; pidState[axis].kP = pidBank()->pid[axis].P / FP_PID_RATE_P_MULTIPLIER * axisTPA; pidState[axis].kI = pidBank()->pid[axis].I / FP_PID_RATE_I_MULTIPLIER; pidState[axis].kD = pidBank()->pid[axis].D / FP_PID_RATE_D_MULTIPLIER * axisTPA; @@ -584,7 +585,11 @@ int16_t angleFreefloatDeadband(int16_t deadband, flight_dynamics_index_t axis) static float computePidLevelTarget(flight_dynamics_index_t axis) { // This is ROLL/PITCH, run ANGLE/HORIZON controllers +#ifdef USE_PROGRAMMING_FRAMEWORK + float angleTarget = pidRcCommandToAngle(getRcCommandOverride(rcCommand, axis), pidProfile()->max_angle_inclination[axis]); +#else float angleTarget = pidRcCommandToAngle(rcCommand[axis], pidProfile()->max_angle_inclination[axis]); +#endif // Automatically pitch down if the throttle is manually controlled and reduced bellow cruise throttle if ((axis == FD_PITCH) && STATE(AIRPLANE) && FLIGHT_MODE(ANGLE_MODE) && !navigationIsControllingThrottle()) { @@ -759,11 +764,12 @@ static void NOINLINE pidApplyFixedWingRateController(pidState_t *pidState, fligh if (!pidState->itermFreezeActive) { pidState->errorGyroIf += rateError * pidState->kI * dT; } - + applyItermLimiting(pidState); - if (pidProfile()->fixedWingItermThrowLimit != 0) { - pidState->errorGyroIf = constrainf(pidState->errorGyroIf, -pidProfile()->fixedWingItermThrowLimit, pidProfile()->fixedWingItermThrowLimit); + if (pidProfile()->pidItermLimitPercent != 0){ + float itermLimit = pidState->pidSumLimit * pidProfile()->pidItermLimitPercent * 0.01f; + pidState->errorGyroIf = constrainf(pidState->errorGyroIf, -itermLimit, +itermLimit); } axisPID[axis] = constrainf(newPTerm + newFFTerm + pidState->errorGyroIf + newDTerm, -pidState->pidSumLimit, +pidState->pidSumLimit); @@ -800,7 +806,7 @@ static float FAST_CODE applyItermRelax(const int axis, float currentPidSetpoint, const float setpointLpf = pt1FilterApply(&windupLpf[axis], currentPidSetpoint); const float setpointHpf = fabsf(currentPidSetpoint - setpointLpf); - const float itermRelaxFactor = MAX(0, 1 - setpointHpf / MC_ITERM_RELAX_SETPOINT_THRESHOLD); + const float itermRelaxFactor = MAX(0, 1 - setpointHpf / (FLIGHT_MODE(ANGLE_MODE) ? (MC_ITERM_RELAX_SETPOINT_THRESHOLD * 0.2f):MC_ITERM_RELAX_SETPOINT_THRESHOLD)); return itermErrorRate * itermRelaxFactor; } } @@ -829,14 +835,27 @@ static void FAST_CODE NOINLINE pidApplyMulticopterRateController(pidState_t *pid const float newOutput = newPTerm + newDTerm + pidState->errorGyroIf + newCDTerm; const float newOutputLimited = constrainf(newOutput, -pidState->pidSumLimit, +pidState->pidSumLimit); + float backCalc = newOutputLimited - newOutput;//back-calculation anti-windup + if (SIGN(backCalc) == SIGN(pidState->errorGyroIf)) { + //back calculation anti-windup can only shrink integrator, will not push it to the opposite direction + backCalc = 0.0f; + } float itermErrorRate = applyItermRelax(axis, rateTarget, rateError); #ifdef USE_ANTIGRAVITY itermErrorRate *= iTermAntigravityGain; #endif - pidState->errorGyroIf += (itermErrorRate * pidState->kI * antiWindupScaler * dT) - + ((newOutputLimited - newOutput) * pidState->kT * antiWindupScaler * dT); + if (!pidState->itermFreezeActive) { + pidState->errorGyroIf += (itermErrorRate * pidState->kI * antiWindupScaler * dT) + + (backCalc * pidState->kT * antiWindupScaler * dT); + } + + if (pidProfile()->pidItermLimitPercent != 0){ + float itermLimit = pidState->pidSumLimit * pidProfile()->pidItermLimitPercent * 0.01f; + pidState->errorGyroIf = constrainf(pidState->errorGyroIf, -itermLimit, +itermLimit); + } + // Don't grow I-term if motors are at their limit applyItermLimiting(pidState); @@ -1033,7 +1052,7 @@ void checkItermLimitingActive(pidState_t *pidState) shouldActivate = isFixedWingItermLimitActive(pidState->stickPosition); } else { - shouldActivate = mixerIsOutputSaturated(); + shouldActivate = mixerIsOutputSaturated(); //just in case, since it is already managed by itermWindupPointPercent } pidState->itermLimitActive = STATE(ANTI_WINDUP) || shouldActivate; @@ -1080,7 +1099,6 @@ void FAST_CODE pidController(float dT) } for (int axis = 0; axis < 3; axis++) { - // Step 1: Calculate gyro rates pidState[axis].gyroRate = gyro.gyroADCf[axis]; // Step 2: Read target @@ -1115,6 +1133,11 @@ void FAST_CODE pidController(float dT) if (FLIGHT_MODE(ANGLE_MODE) || FLIGHT_MODE(HORIZON_MODE) || isFlightAxisAngleOverrideActive(axis)) { //If axis angle override, get the correct angle from Logic Conditions float angleTarget = getFlightAxisAngleOverride(axis, computePidLevelTarget(axis)); + + //apply 45 deg offset for tailsitter when isMixerTransitionMixing is activated + if (STATE(TAILSITTER) && isMixerTransitionMixing && axis == FD_PITCH){ + angleTarget += DEGREES_TO_DECIDEGREES(45); + } //Apply the Level PID controller pidLevel(angleTarget, &pidState[axis], axis, horizonRateMagnitude, dT); @@ -1134,8 +1157,8 @@ void FAST_CODE pidController(float dT) pidApplyFpvCameraAngleMix(pidState, currentControlRateProfile->misc.fpvCamAngleDegrees); } - // Prevent strong Iterm accumulation during stick inputs - antiWindupScaler = constrainf((1.0f - getMotorMixRange()) * motorItermWindupPoint, 0.0f, 1.0f); + // Prevent Iterm accumulation when motors are near its saturation + antiWindupScaler = constrainf((1.0f - getMotorMixRange() * MAX(2*motorItermWindupPoint,1)) * motorItermWindupPoint_inv, 0.0f, 1.0f); for (int axis = 0; axis < 3; axis++) { // Apply setpoint rate of change limits @@ -1177,7 +1200,9 @@ void pidInit(void) itermRelax = pidProfile()->iterm_relax; yawLpfHz = pidProfile()->yaw_lpf_hz; - motorItermWindupPoint = 1.0f / (1.0f - (pidProfile()->itermWindupPointPercent / 100.0f)); + motorItermWindupPoint = 1.0f - (pidProfile()->itermWindupPointPercent / 100.0f); + motorItermWindupPoint_inv = 1.0f / motorItermWindupPoint; + #ifdef USE_D_BOOST dBoostMin = pidProfile()->dBoostMin; diff --git a/src/main/flight/pid.h b/src/main/flight/pid.h index de0e3126b7c..7c61b7cec21 100644 --- a/src/main/flight/pid.h +++ b/src/main/flight/pid.h @@ -31,10 +31,6 @@ #define HEADING_HOLD_RATE_LIMIT_MAX 250 #define HEADING_HOLD_RATE_LIMIT_DEFAULT 90 -#define FW_ITERM_THROW_LIMIT_DEFAULT 165 -#define FW_ITERM_THROW_LIMIT_MIN 0 -#define FW_ITERM_THROW_LIMIT_MAX 500 - #define AXIS_ACCEL_MIN_LIMIT 50 #define HEADING_HOLD_ERROR_LPF_FREQ 2 @@ -121,9 +117,9 @@ typedef struct pidProfile_s { uint16_t pidSumLimit; uint16_t pidSumLimitYaw; + uint16_t pidItermLimitPercent; // Airplane-specific parameters - uint16_t fixedWingItermThrowLimit; float fixedWingReferenceAirspeed; // Reference tuning airspeed for the airplane - the speed for which PID gains are tuned float fixedWingCoordinatedYawGain; // This is the gain of the yaw rate required to keep the yaw rate consistent with the turn rate for a coordinated turn. float fixedWingCoordinatedPitchGain; // This is the gain of the pitch rate to keep the pitch angle constant during coordinated turns. diff --git a/src/main/msp/msp_protocol_v2_inav.h b/src/main/msp/msp_protocol_v2_inav.h index 9cf1881c732..9b4abbdbe45 100755 --- a/src/main/msp/msp_protocol_v2_inav.h +++ b/src/main/msp/msp_protocol_v2_inav.h @@ -94,3 +94,5 @@ #define MSP2_INAV_RATE_DYNAMICS 0x2060 #define MSP2_INAV_SET_RATE_DYNAMICS 0x2061 + +#define MSP2_INAV_SELECT_MIXER_PROFILE 0x2070 diff --git a/src/main/sensors/boardalignment.c b/src/main/sensors/boardalignment.c index 86e41880f89..1f149faeff6 100644 --- a/src/main/sensors/boardalignment.c +++ b/src/main/sensors/boardalignment.c @@ -28,6 +28,7 @@ #include "config/parameter_group.h" #include "config/parameter_group_ids.h" +#include "fc/runtime_config.h" #include "drivers/sensor.h" @@ -45,6 +46,7 @@ static bool standardBoardAlignment = true; // board orientation correction static fpMat3_t boardRotMatrix; +static fpMat3_t tailRotMatrix; // no template required since defaults are zero PG_REGISTER(boardAlignment_t, boardAlignment, PG_BOARD_ALIGNMENT, 0); @@ -56,19 +58,19 @@ static bool isBoardAlignmentStandard(const boardAlignment_t *boardAlignment) void initBoardAlignment(void) { - if (isBoardAlignmentStandard(boardAlignment())) { - standardBoardAlignment = true; - } else { - fp_angles_t rotationAngles; - - standardBoardAlignment = false; - - rotationAngles.angles.roll = DECIDEGREES_TO_RADIANS(boardAlignment()->rollDeciDegrees ); - rotationAngles.angles.pitch = DECIDEGREES_TO_RADIANS(boardAlignment()->pitchDeciDegrees); - rotationAngles.angles.yaw = DECIDEGREES_TO_RADIANS(boardAlignment()->yawDeciDegrees ); - - rotationMatrixFromAngles(&boardRotMatrix, &rotationAngles); - } + standardBoardAlignment=isBoardAlignmentStandard(boardAlignment()); + fp_angles_t rotationAngles; + + rotationAngles.angles.roll = DECIDEGREES_TO_RADIANS(boardAlignment()->rollDeciDegrees ); + rotationAngles.angles.pitch = DECIDEGREES_TO_RADIANS(boardAlignment()->pitchDeciDegrees); + rotationAngles.angles.yaw = DECIDEGREES_TO_RADIANS(boardAlignment()->yawDeciDegrees ); + + rotationMatrixFromAngles(&boardRotMatrix, &rotationAngles); + fp_angles_t tailSitter_rotationAngles; + tailSitter_rotationAngles.angles.roll = DECIDEGREES_TO_RADIANS(0); + tailSitter_rotationAngles.angles.pitch = DECIDEGREES_TO_RADIANS(900); + tailSitter_rotationAngles.angles.yaw = DECIDEGREES_TO_RADIANS(0); + rotationMatrixFromAngles(&tailRotMatrix, &tailSitter_rotationAngles); } void updateBoardAlignment(int16_t roll, int16_t pitch) @@ -85,15 +87,23 @@ void updateBoardAlignment(int16_t roll, int16_t pitch) initBoardAlignment(); } +void applyTailSitterAlignment(fpVector3_t *fpVec) +{ + if (!STATE(TAILSITTER)) { + return; + } + rotationMatrixRotateVector(fpVec, fpVec, &tailRotMatrix); +} + void applyBoardAlignment(float *vec) { - if (standardBoardAlignment) { + if (standardBoardAlignment && (!STATE(TAILSITTER))) { return; } fpVector3_t fpVec = { .v = { vec[X], vec[Y], vec[Z] } }; rotationMatrixRotateVector(&fpVec, &fpVec, &boardRotMatrix); - + applyTailSitterAlignment(&fpVec); vec[X] = lrintf(fpVec.x); vec[Y] = lrintf(fpVec.y); vec[Z] = lrintf(fpVec.z); diff --git a/src/main/sensors/boardalignment.h b/src/main/sensors/boardalignment.h index 6bf01272650..17cd08e5ff3 100644 --- a/src/main/sensors/boardalignment.h +++ b/src/main/sensors/boardalignment.h @@ -18,6 +18,7 @@ #pragma once #include "config/parameter_group.h" +#include "common/vector.h" typedef struct boardAlignment_s { int16_t rollDeciDegrees; @@ -30,4 +31,5 @@ PG_DECLARE(boardAlignment_t, boardAlignment); void initBoardAlignment(void); void updateBoardAlignment(int16_t roll, int16_t pitch); void applySensorAlignment(float * dest, float * src, uint8_t rotation); -void applyBoardAlignment(float *vec); \ No newline at end of file +void applyBoardAlignment(float *vec); +void applyTailSitterAlignment(fpVector3_t *vec); \ No newline at end of file diff --git a/src/main/sensors/compass.c b/src/main/sensors/compass.c index 23d45ed7879..734a1e98224 100644 --- a/src/main/sensors/compass.c +++ b/src/main/sensors/compass.c @@ -472,7 +472,7 @@ void compassUpdate(timeUs_t currentTimeUs) fpVector3_t rotated; rotationMatrixRotateVector(&rotated, &v, &mag.dev.magAlign.externalRotation); - + applyTailSitterAlignment(&rotated); mag.magADC[X] = rotated.x; mag.magADC[Y] = rotated.y; mag.magADC[Z] = rotated.z;