5 #include "config/feature.h"
6 #include "config/parameter_group.h"
7 #include "config/parameter_group_ids.h"
8 #include "config/config_reset.h"
10 #include "drivers/pwm_output.h"
11 #include "drivers/pwm_mapping.h"
12 #include "drivers/time.h"
13 #include "flight/mixer.h"
14 #include "common/axis.h"
15 #include "flight/pid.h"
16 #include "flight/servos.h"
17 #include "flight/failsafe.h"
18 #include "navigation/navigation.h"
19 #include "navigation/navigation_private.h"
21 #include "fc/fc_core.h"
22 #include "fc/config.h"
23 #include "fc/runtime_config.h"
24 #include "fc/settings.h"
25 #include "fc/rc_modes.h"
28 #include "programming/logic_condition.h"
29 #include "navigation/navigation.h"
31 #include "common/log.h"
33 mixerConfig_t currentMixerConfig
;
34 int currentMixerProfileIndex
;
35 bool isMixerTransitionMixing
;
36 bool isMixerTransitionMixing_requested
;
37 mixerProfileAT_t mixerProfileAT
;
38 int nextMixerProfileIndex
;
40 PG_REGISTER_ARRAY_WITH_RESET_FN(mixerProfile_t
, MAX_MIXER_PROFILE_COUNT
, mixerProfiles
, PG_MIXER_PROFILE
, 1);
42 void pgResetFn_mixerProfiles(mixerProfile_t
*instance
)
44 for (int i
= 0; i
< MAX_MIXER_PROFILE_COUNT
; i
++)
46 RESET_CONFIG(mixerProfile_t
, &instance
[i
],
48 .motorDirectionInverted
= SETTING_MOTOR_DIRECTION_INVERTED_DEFAULT
,
49 .platformType
= SETTING_PLATFORM_TYPE_DEFAULT
,
50 .hasFlaps
= SETTING_HAS_FLAPS_DEFAULT
,
51 .appliedMixerPreset
= SETTING_MODEL_PREVIEW_TYPE_DEFAULT
, // This flag is not available in CLI and used by Configurator only
52 .motorstopOnLow
= SETTING_MOTORSTOP_ON_LOW_DEFAULT
,
53 .PIDProfileLinking
= SETTING_MIXER_PID_PROFILE_LINKING_DEFAULT
,
54 .automated_switch
= SETTING_MIXER_AUTOMATED_SWITCH_DEFAULT
,
55 .switchTransitionTimer
= SETTING_MIXER_SWITCH_TRANS_TIMER_DEFAULT
,
56 .tailsitterOrientationOffset
= SETTING_TAILSITTER_ORIENTATION_OFFSET_DEFAULT
,
58 for (int j
= 0; j
< MAX_SUPPORTED_MOTORS
; j
++)
60 RESET_CONFIG(motorMixer_t
, &instance
[i
].MotorMixers
[j
],
66 for (int j
= 0; j
< MAX_SERVO_RULES
; j
++)
68 RESET_CONFIG(servoMixer_t
, &instance
[i
].ServoMixers
[j
],
73 #ifdef USE_PROGRAMMING_FRAMEWORK
82 void activateMixerConfig(void){
83 currentMixerProfileIndex
= getConfigMixerProfile();
84 currentMixerConfig
= *mixerConfig();
85 nextMixerProfileIndex
= (currentMixerProfileIndex
+ 1) % MAX_MIXER_PROFILE_COUNT
;
88 void mixerConfigInit(void)
90 activateMixerConfig();
92 mixerUpdateStateFlags();
94 if (currentMixerConfig
.PIDProfileLinking
)
96 // LOG_INFO(PWM, "mixer switch pidInit");
97 setConfigProfile(getConfigMixerProfile());
100 pidResetErrorAccumulators(); //should be safer to reset error accumulators
101 schedulePidGainsUpdate();
102 navigationUsePIDs(); // set navigation pid gains
106 void setMixerProfileAT(void)
108 mixerProfileAT
.transitionStartTime
= millis();
109 mixerProfileAT
.transitionTransEndTime
= mixerProfileAT
.transitionStartTime
+ (timeMs_t
)currentMixerConfig
.switchTransitionTimer
* 100;
112 bool platformTypeConfigured(flyingPlatformType_e platformType
)
114 if (!isModeActivationConditionPresent(BOXMIXERPROFILE
)){
117 return mixerConfigByIndex(nextMixerProfileIndex
)->platformType
== platformType
;
120 bool checkMixerATRequired(mixerProfileATRequest_e required_action
)
122 //return false if mixerAT condition is not required or setting is not valid
123 if ((!STATE(AIRPLANE
)) && (!STATE(MULTIROTOR
)))
127 if (!isModeActivationConditionPresent(BOXMIXERPROFILE
))
132 if(currentMixerConfig
.automated_switch
){
133 if ((required_action
== MIXERAT_REQUEST_RTH
) && STATE(MULTIROTOR
))
137 if ((required_action
== MIXERAT_REQUEST_LAND
) && STATE(AIRPLANE
))
145 bool mixerATUpdateState(mixerProfileATRequest_e required_action
)
147 //return true if mixerAT is done or not required
151 reprocessState
=false;
152 if (required_action
==MIXERAT_REQUEST_ABORT
){
153 isMixerTransitionMixing_requested
= false;
154 mixerProfileAT
.phase
= MIXERAT_PHASE_IDLE
;
157 switch (mixerProfileAT
.phase
){
158 case MIXERAT_PHASE_IDLE
:
159 //check if mixerAT is required
160 if (checkMixerATRequired(required_action
)){
161 mixerProfileAT
.phase
=MIXERAT_PHASE_TRANSITION_INITIALIZE
;
162 reprocessState
= true;
165 case MIXERAT_PHASE_TRANSITION_INITIALIZE
:
166 // LOG_INFO(PWM, "MIXERAT_PHASE_IDLE");
168 mixerProfileAT
.phase
= MIXERAT_PHASE_TRANSITIONING
;
169 reprocessState
= true;
171 case MIXERAT_PHASE_TRANSITIONING
:
172 isMixerTransitionMixing_requested
= true;
173 if (millis() > mixerProfileAT
.transitionTransEndTime
){
174 isMixerTransitionMixing_requested
= false;
175 outputProfileHotSwitch(nextMixerProfileIndex
);
176 mixerProfileAT
.phase
= MIXERAT_PHASE_IDLE
;
177 reprocessState
= true;
186 while (reprocessState
);
190 bool checkMixerProfileHotSwitchAvalibility(void)
192 if (MAX_MIXER_PROFILE_COUNT
!= 2)
199 void outputProfileUpdateTask(timeUs_t currentTimeUs
)
201 UNUSED(currentTimeUs
);
203 bool mixerAT_inuse
= mixerProfileAT
.phase
!= MIXERAT_PHASE_IDLE
;
204 // transition mode input for servo mix and motor mix
205 if (!FLIGHT_MODE(FAILSAFE_MODE
) && (!mixerAT_inuse
))
207 if (isModeActivationConditionPresent(BOXMIXERPROFILE
)){
208 outputProfileHotSwitch(IS_RC_MODE_ACTIVE(BOXMIXERPROFILE
) == 0 ? 0 : 1);
210 isMixerTransitionMixing_requested
= IS_RC_MODE_ACTIVE(BOXMIXERTRANSITION
);
212 isMixerTransitionMixing
= isMixerTransitionMixing_requested
&& ((posControl
.navState
== NAV_STATE_IDLE
) || mixerAT_inuse
||(posControl
.navState
== NAV_STATE_ALTHOLD_IN_PROGRESS
));
215 // switch mixerprofile without reboot
216 bool outputProfileHotSwitch(int profile_index
)
218 static bool allow_hot_switch
= true;
219 // LOG_INFO(PWM, "OutputProfileHotSwitch");
220 if (!allow_hot_switch
)
224 if (currentMixerProfileIndex
== profile_index
)
228 if (profile_index
< 0 || profile_index
>= MAX_MIXER_PROFILE_COUNT
)
230 // LOG_INFO(PWM, "invalid mixer profile index");
233 if (areSensorsCalibrating())
234 { // it seems like switching before sensors calibration complete will cause pid stops to respond, especially in D
237 if (!checkMixerProfileHotSwitchAvalibility())
239 // LOG_INFO(PWM, "mixer switch failed, checkMixerProfileHotSwitchAvalibility");
242 if ((posControl
.navState
!= NAV_STATE_IDLE
) && (posControl
.navState
!= NAV_STATE_MIXERAT_IN_PROGRESS
))
244 // LOG_INFO(PWM, "mixer switch failed, navState != NAV_STATE_IDLE");
247 if (!setConfigMixerProfile(profile_index
))
249 // LOG_INFO(PWM, "mixer switch failed to set config");