@@ -5,12 +5,13 @@ namespace Espfc {
5
5
6
6
namespace Control {
7
7
8
- Controller::Controller (Model& model): _model(model) {}
8
+ Controller::Controller (Model& model): _model(model), _altitude(model) {}
9
9
10
10
int Controller::begin ()
11
11
{
12
12
_rates.begin (_model.config .input );
13
13
_speedFilter.begin (FilterConfig (FILTER_BIQUAD, 10 ), _model.state .loopTimer .rate );
14
+ _altitude.begin ();
14
15
return 1 ;
15
16
}
16
17
@@ -25,26 +26,31 @@ int FAST_CODE_ATTR Controller::update()
25
26
26
27
{
27
28
Utils::Stats::Measure (_model.state .stats , COUNTER_OUTER_PID);
29
+ _altitude.update ();
28
30
resetIterm ();
29
- if (_model.config .mixer .type == FC_MIXER_GIMBAL )
31
+ switch (_model.config .mixer .type )
30
32
{
31
- outerLoopRobot ();
32
- }
33
- else
34
- {
35
- outerLoop ();
33
+ case FC_MIXER_GIMBAL:
34
+ outerLoopRobot ();
35
+ break ;
36
+
37
+ default :
38
+ outerLoop ();
39
+ break ;
36
40
}
37
41
}
38
42
39
43
{
40
44
Utils::Stats::Measure (_model.state .stats , COUNTER_INNER_PID);
41
- if (_model.config .mixer .type == FC_MIXER_GIMBAL)
42
- {
43
- innerLoopRobot ();
44
- }
45
- else
45
+ switch (_model.config .mixer .type )
46
46
{
47
- innerLoop ();
47
+ case FC_MIXER_GIMBAL:
48
+ innerLoopRobot ();
49
+ break ;
50
+
51
+ default :
52
+ innerLoop ();
53
+ break ;
48
54
}
49
55
}
50
56
@@ -110,27 +116,44 @@ void Controller::innerLoopRobot()
110
116
111
117
void FAST_CODE_ATTR Controller::outerLoop ()
112
118
{
119
+ // Roll/Pitch rates control
113
120
if (_model.isModeActive (MODE_ANGLE))
114
121
{
115
- _model.state .setpoint .angle = VectorFloat (
116
- _model.state .input .ch [AXIS_ROLL] * Utils::toRad (_model.config .level .angleLimit ),
117
- _model.state .input .ch [AXIS_PITCH] * Utils::toRad (_model.config .level .angleLimit ),
118
- _model.state .attitude .euler [AXIS_YAW]
119
- );
120
- _model.state .setpoint .rate [AXIS_ROLL] = _model.state .outerPid [AXIS_ROLL].update (_model.state .setpoint .angle [AXIS_ROLL], _model.state .attitude .euler [AXIS_ROLL]);
121
- _model.state .setpoint .rate [AXIS_PITCH] = _model.state .outerPid [AXIS_PITCH].update (_model.state .setpoint .angle [AXIS_PITCH], _model.state .attitude .euler [AXIS_PITCH]);
122
- // disable fterm in angle mode
123
- _model.state .innerPid [AXIS_ROLL].fScale = 0 .f ;
124
- _model.state .innerPid [AXIS_PITCH].fScale = 0 .f ;
122
+ for (size_t i = 0 ; i < AXIS_COUNT_RP; i++)
123
+ {
124
+ const float angleSetpoint = Utils::toRad (_model.config .level .angleLimit ) * _model.state .input .ch [i];
125
+ _model.state .setpoint .rate [i] = _model.state .outerPid [i].update (angleSetpoint, _model.state .attitude .euler [i]);
126
+ // disable fterm in angle mode
127
+ _model.state .innerPid [i].fScale = 0 .f ;
128
+ }
125
129
}
126
130
else
127
131
{
128
- _model.state .setpoint .rate [AXIS_ROLL] = calculateSetpointRate (AXIS_ROLL, _model.state .input .ch [AXIS_ROLL]);
129
- _model.state .setpoint .rate [AXIS_PITCH] = calculateSetpointRate (AXIS_PITCH, _model.state .input .ch [AXIS_PITCH]);
132
+ for (size_t i = 0 ; i < AXIS_COUNT_RP; i++)
133
+ {
134
+ _model.state .setpoint .rate [i] = calculateSetpointRate (i, _model.state .input .ch [i]);
135
+ }
130
136
}
137
+
138
+ // Yaw rates control
131
139
_model.state .setpoint .rate [AXIS_YAW] = calculateSetpointRate (AXIS_YAW, _model.state .input .ch [AXIS_YAW]);
132
- _model.state .setpoint .rate [AXIS_THRUST] = _model.state .input .ch [AXIS_THRUST];
133
140
141
+ // thrust control
142
+ if (_model.isModeActive (MODE_ALTHOLD))
143
+ {
144
+ _model.state .setpoint .rate [AXIS_THRUST] = calcualteAltHoldSetpoint ();
145
+ if (_model.config .debug .mode == DEBUG_ALTITUDE)
146
+ {
147
+ _model.state .debug [0 ] = lrintf (_model.state .input .ch [AXIS_THRUST] * 1000 .0f );
148
+ _model.state .debug [1 ] = lrintf (_model.state .setpoint .rate [AXIS_THRUST] * 1000 .0f );
149
+ }
150
+ }
151
+ else
152
+ {
153
+ _model.state .setpoint .rate [AXIS_THRUST] = _model.state .input .ch [AXIS_THRUST];
154
+ }
155
+
156
+ // debug
134
157
if (_model.config .debug .mode == DEBUG_ANGLERATE)
135
158
{
136
159
for (size_t i = 0 ; i < AXIS_COUNT_RPY; ++i)
@@ -142,14 +165,29 @@ void FAST_CODE_ATTR Controller::outerLoop()
142
165
143
166
void FAST_CODE_ATTR Controller::innerLoop ()
144
167
{
168
+ // Roll/Pitch/Yaw rates control
145
169
const float tpaFactor = getTpaFactor ();
146
170
for (size_t i = 0 ; i < AXIS_COUNT_RPY; ++i)
147
171
{
148
172
_model.state .output .ch [i] = _model.state .innerPid [i].update (_model.state .setpoint .rate [i], _model.state .gyro .adc [i]) * tpaFactor;
149
- // _model.state.debug[i] = lrintf(_model.state.innerPid[i].fTerm * 1000);
150
173
}
151
- _model.state .output .ch [AXIS_THRUST] = _model.state .setpoint .rate [AXIS_THRUST];
152
174
175
+ // thrust control
176
+ if (_model.isModeActive (MODE_ALTHOLD))
177
+ {
178
+ _model.state .output .ch [AXIS_THRUST] = _model.state .innerPid [AXIS_THRUST].update (_model.state .setpoint .rate [AXIS_THRUST], _model.state .altitude .rate );
179
+ if (_model.config .debug .mode == DEBUG_ALTITUDE)
180
+ {
181
+ _model.state .debug [2 ] = lrintf (_model.state .output .ch [AXIS_THRUST] * 1000 .0f );
182
+ _model.state .debug [3 ] = lrintf (_model.state .innerPid [AXIS_THRUST].iTerm * 1000 .0f );
183
+ }
184
+ }
185
+ else
186
+ {
187
+ _model.state .output .ch [AXIS_THRUST] = _model.state .setpoint .rate [AXIS_THRUST];
188
+ }
189
+
190
+ // debug
153
191
if (_model.config .debug .mode == DEBUG_ITERM_RELAX)
154
192
{
155
193
_model.state .debug [0 ] = lrintf (Utils::toDeg (_model.state .innerPid [0 ].itermRelaxBase ));
@@ -159,6 +197,17 @@ void FAST_CODE_ATTR Controller::innerLoop()
159
197
}
160
198
}
161
199
200
+ float Controller::calcualteAltHoldSetpoint () const
201
+ {
202
+ float thrust = _model.state .input .ch [AXIS_THRUST];
203
+
204
+ if (_model.isThrottleLow ()) thrust = 0 .0f ; // stick below min check, no command
205
+
206
+ thrust = Utils::deadband (thrust, 0 .125f ); // +/- 12.5% deadband
207
+
208
+ return thrust * 0 .5f ; // climb/descend rate factor 0.5 m/s
209
+ }
210
+
162
211
float Controller::getTpaFactor () const
163
212
{
164
213
if (_model.config .controller .tpaScale == 0 ) return 1 .f ;
@@ -172,15 +221,19 @@ void Controller::resetIterm()
172
221
|| (!_model.isAirModeActive () && _model.config .iterm .lowThrottleZeroIterm && _model.isThrottleLow ()) // on low throttle (not in air mode)
173
222
)
174
223
{
175
- for (size_t i = 0 ; i < AXIS_COUNT_RPYT ; i++)
224
+ for (size_t i = 0 ; i < AXIS_COUNT_RPY ; i++)
176
225
{
177
- _model.state .innerPid [i].iTerm = 0 ;
178
- _model.state .outerPid [i].iTerm = 0 ;
226
+ _model.state .innerPid [i].iTerm = 0 . 0f ;
227
+ _model.state .outerPid [i].iTerm = 0 . 0f ;
179
228
}
180
229
}
230
+ if (!_model.isModeActive (MODE_ARMED))
231
+ {
232
+ _model.state .innerPid [AXIS_THRUST].iTerm = 0 .0f ;
233
+ }
181
234
}
182
235
183
- float Controller::calculateSetpointRate (int axis, float input)
236
+ float Controller::calculateSetpointRate (int axis, float input) const
184
237
{
185
238
if (axis == AXIS_YAW) input *= -1 .f ;
186
239
return _rates.getSetpoint (axis, input);
0 commit comments