Subversion Repositories FlightCtrl

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1068 thjac 1
/* pitch.c
2
 *
3
 * Pitch-Steuerung
4
 */
5
 
6
#include "main.h"
7
#include "fc.h"
8
#include "pitch.h"
9
 
10
#define STATE_STARTUP_WAIT              0x00                    // Init-Timeout beim Einschalten abwarten
11
#define STATE_STARTUP_INIT              0x01                    // Initialisierung beim Einschalten
12
#define STATE_BEGIN                     0x02                    // Anfangszustand nach Einschalten der Motoren
13
#define STATE_INITIALIZING              0x03                    // Initialisierungsphase
14
#define STATE_MANUAL                    0x04                    // Manuelle Kontrolle, Höhenregelung in Konfiguration deaktiviert
15
#define STATE_INACTIVE                  0x05                    // Manuelle Kontrolle
16
#define STATE_WAIT                      0x06                    // Warten auf Einschalten der Höhenregelung
17
#define STATE_ACTIVATING                0x07                    // Aktivierung der Höhenregelung
18
#define STATE_ACTIVE                    0x08                    // Höhenregelung ist aktiv
19
 
20
#define PARAM_INIT_TIMEOUT              25
21
 
22
 
23
char    initTimer               = PARAM_INIT_TIMEOUT;
24
int     stickValue              = 0;                            // Aktueller Stick-Wert
25
int     lastStickValue          = 0;                            // Vorheriger Stick-Wert
26
int     zeroStickOffset         = 0;                            // Offset für Stick-Kalibrierung
27
int     pitchOffset             = 0;                            // Aktueller Grundgaswert in Neutralstellung
28
char    state                   = STATE_STARTUP_WAIT;           // Zustand
29
 
30
/* Wird verwendet, um das Umschalten auf automatische Höhenregelung
31
 * nach Erreichen der Neutralstellung zu verzögern.
32
 */
33
int     pitchNeutralTimer       = PITCH_NEUTRAL_TIMER;
34
 
35
// Variable zur Höhenregelung
36
int     pressureOffset          = 0;
37
int     accZOffset              = 0;
38
int     lastAirPressure         = 0;
39
int     lastN                   = 0;                            // Zuletzt errechneter Fehlerwert
40
long    altIntegral             = 0;
41
int     temp;                                                   // Temporäre Werte; wird mehrfach verwendet
42
 
43
extern unsigned char Notlandung;                                // aus fc.c
44
 
45
 
46
/*
47
 * Berechnet den aktuellen Pitch-Wert für die Regelung
48
 *
49
 * Nach dem Einschalten der FC wird der aktuelle Gas-Stick-Wert gelesen und als Kalibrierungswert
50
 * für die Neutralstellung gespeichert. Somit spielt die korrekte Trimmung des Sticks auf Senderseite
51
 * keine Rolle.
52
 *
53
 * Nach Einschalten der Motoren geht der Stick in Neutralstellung. Diese Stick-Bewegung wird ignoriert
54
 * und die Motoren drehen mit dem eingestellten MinGas2. Ausgehend von der Neutralstellung wird nun
55
 * durch Bewegen des Sticks im oberen Bereich das Gas geregelt.
56
 *
57
 * Das erstmalige Aktivieren der automatischen Höhenregelung erfolgt durch Loslassen des Sticks im
58
 * Schwebeflug. Der zuvor aktuelle Stick-Wert wird als Wert in Neutralstellung übernommen und die
59
 * automatische Höhenregelung sofort aktiviert.
60
 *
61
 * Sobald der Stick die Neutralstellung verläßt, wird die automatische Höhenregelung deaktiviert
62
 * und der vorige Pitch-Wert als Wert der Neutralstellung übernommen. Der Pitch läßt sich nun
63
 * über den gesamten Stick-Bereich regeln.
64
 *
65
 * Erreicht der Stick ein weiteres Mal die Neutralstellung, wird die automatische Höhenregelung
66
 * wieder aktiviert, jetzt jedoch immer mit einer zeitlichen Verzögerung. Nur so ist ein
67
 * ungestörtes manuelles Steuern möglich.
68
 *
69
 * Der Pitch-Wert ist innerhalb der Regelung durch ein konfigurierbares Minimalgas nach unten begrenzt.
70
 * Dieses Minimalgas kann auf einen sehr niedrigen Wert eingestellt sein. Um im Flug nicht unterhalb
71
 * eines Wertes zu gelangen, der die Lageregelung außer Funktion setzt, wird ein zweiter Wert für
72
 * Minimalgas konfiguriert, der greift, sobald erstmalig die automatische Höhenregelung aktiviert wurde.
73
 */
74
int pitch( void ) {
75
 
76
        int register pitchCount;
77
 
78
        // Sind die Motoren eingeschaltet?
79
        if( MotorenEin ) {
80
 
81
                // Vorigen Stick-Wert merken
82
                lastStickValue = stickValue;
83
 
84
                /* StickValue exponentiell angleichen, da ausgehend von der Neutralstellung
85
                 * nur jeweils die halbe Auflösung nach oben und unten zur Verfügung steht. Bei einer
86
                 * Multiplikation mit 2 ließe sich das Gas im Schwebebereich nicht fein genug einstellen. */
87
                temp = PPM_in[ EE_Parameter.Kanalbelegung[ K_GAS ] ] - zeroStickOffset;
88
                if( temp > 0 ) {
89
                        temp = temp + ( ( temp * temp ) / 150 );
90
                } else {
91
                        temp = temp - ( ( temp * temp ) / 150 );
92
                }
93
 
94
                // Original-Stick-Wert holen und glätten
95
                stickValue = ( temp + 2 * lastStickValue ) / 3;
96
 
97
                /* Aktuellen Pitch-Wert berechnen. Der Wert ergibt sich aus dem Pitch-Offset
98
                 * zuzüglich dem Stick-Wert. */
99
                pitchCount = stickValue + pitchOffset;
100
 
101
                switch( state ) {
102
 
103
                        case STATE_BEGIN:
104
 
105
                                // Schnelles Bewegen aus dem oberen Bereich des Sticks in Neutralstellung
106
                                if( ( lastStickValue > PITCH_STICK_THRESHOLD ) &&
107
                                ( lastStickValue > stickValue ) &&
108
                                ( lastStickValue - stickValue >= PITCH_NEUTRAL_DIFF ) ) {
109
 
110
                                        pitchOffset += lastStickValue;
111
                                        state        = STATE_INITIALIZING;
112
                                }
113
                                break;
114
 
115
                        case STATE_INITIALIZING:
116
 
117
                                if( abs( stickValue ) > PITCH_STICK_THRESHOLD ) {
118
                                        pitchCount = pitchOffset;
119
                                } else {
120
 
121
                                        // Ist die Höhenregelung aktiviert?
122
                                        if( EE_Parameter.GlobalConfig & CFG_HOEHENREGELUNG ) {
123
                                                state = STATE_ACTIVATING;
124
                                        } else {
125
                                                state = STATE_MANUAL;
126
                                        }
127
                                }
128
                                break;
129
 
130
                        /* Wenn die Höhenregelung per Konfiguration deaktiviert ist, verbleibt
131
                         * die Funktion in diesem Zustand. */
132
                        case STATE_MANUAL:
133
 
134
                                // Min2-Gas einstellen für Lageregelung bei Minimalgas
135
                                if( pitchCount < PITCH_MIN2 ) {
136
                                        pitchCount = PITCH_MIN2;
137
                                }
138
                                break;
139
 
140
                        /* Die Höhenregelung ist per Konfiguration aktiviert, jedoch befindet
141
                         * sich der Stick außerhalb des als Neutralstellung anerkannten
142
                         * Wertebereiches. Es wird manuell geregelt. */
143
                        case STATE_INACTIVE:
144
 
145
                                // Min2-Gas einstellen für Lageregelung bei Minimalgas
146
                                if( pitchCount < PITCH_MIN2 ) {
147
                                        pitchCount = PITCH_MIN2;
148
                                }
149
 
150
                                // Stick ist innerhalb der Neutralstellung
151
                                if( abs( stickValue ) < PITCH_STICK_THRESHOLD ) {
152
 
153
                                        // Timer neu setzen
154
                                        pitchNeutralTimer = PITCH_NEUTRAL_TIMER;
155
                                        state             = STATE_WAIT;
156
                                }
157
                                break;
158
 
159
                        /* Der Stick ist in den für die Neutralstellung gültigen Wertebereich
160
                         * gelangt. Nun darf innerhalb einer bestimmten Zeit keine Stick-Bewegung
161
                         * erfolgen, um die automatische Höhenregelung zu aktivieren. */
162
                        case STATE_WAIT:
163
 
164
                                /* Stick ist innerhalb der Neutralstellung und
165
                                   Stick-Differenzial ist < 2 */
166
                                if( abs( stickValue ) < PITCH_STICK_THRESHOLD &&
167
                                    abs( lastStickValue - stickValue ) < 2 ) {
168
 
169
                                        pitchNeutralTimer--;
170
 
171
                                        if( !pitchNeutralTimer ) {
172
                                                state = STATE_ACTIVATING;
173
                                        }
174
 
175
                                // Aktivierungskriterium nicht erfüllt, zurück in INACTIVE
176
                                } else {
177
                                        state = STATE_INACTIVE;
178
                                }
179
                                break;
180
 
181
                        /* Die automatische Höhenregelung wird jetzt aktiviert. Der aktuelle
182
                         * Luftdruck wird gespeichert und notwendige Werte für den Regler
183
                         * werden initialisiert. */
184
                        case STATE_ACTIVATING:
185
 
186
                                // Die Referenzhöhe soll zu Beginn der Neutralstellung genommen werden
187
                                pressureOffset = airPressure;
188
                                accZOffset     = Mess_Integral_Hoch / 128;
189
 
190
                                lastAirPressure = 0;
191
                                lastN        = 0;
192
                                altIntegral  = 0L;
193
                                state        = STATE_ACTIVE;
194
 
195
                                // Einschalten der Höhenregelung signalisieren
196
                                beeptime     = 500;
197
 
198
                                break;
199
 
200
                        /* Die automatische Höhenregelung ist aktiv. */                
201
                        case STATE_ACTIVE:
202
 
203
                                // Stick ist außerhalb der Neutralstellung
204
                                if( abs( stickValue ) > PITCH_STICK_THRESHOLD ) {
205
                                        pitchOffset -= lastN / 4;
206
                                        pitchCount   = stickValue + pitchOffset;
207
                                        lastN        = 0;
208
                                        state        = STATE_INACTIVE;
209
 
210
                                        // Abschaltung der Höhenregelung signalisieren
211
                                        beeptime     = 500;
212
                                }
213
                                break;
214
                }
215
 
216
        // Motoren sind aus
217
        } else {
218
 
219
                switch( state ) {
220
 
221
                        case STATE_STARTUP_WAIT:
222
 
223
                                if( !initTimer-- ) {
224
                                        state = STATE_STARTUP_INIT;
225
                                }
226
                                break;
227
 
228
                        case STATE_STARTUP_INIT:
229
 
230
                                /* Lädt den beim Einschalten der FC anliegenden Stickwert als
231
                                 * Offset für die Kalibrierung des Gas-Sticks. */
232
                                zeroStickOffset = PPM_in[ EE_Parameter.Kanalbelegung[ K_GAS ] ];
233
 
234
                                // Die Einschaltphase ist jetzt beendet
235
                                state    = STATE_BEGIN;
236
 
237
                                break;
238
 
239
                        default:
240
 
241
                                /* Nach dem Einschalten der Motoren darf pitchOffset keinen hohen Wert haben,
242
                                 * da der Kopter sonst sofort hochschießen würde.
243
                                 */
244
                                pitchCount  = 0;
245
                                pitchOffset = 0;
246
                                stickValue  = 0;
247
                                state       = STATE_BEGIN;
248
                }
249
        }
250
 
251
        if( pitchOffset < 0 )
252
                pitchOffset = 0;
253
 
254
        // Pitch-Wert darf nicht < 0 sein
255
        if( pitchCount < 0 ) {
256
                pitchCount = 0;
257
        }
258
 
259
        // pitchCount als Debug-Wert rausschreiben
260
        DebugOut.Analog[28] = pitchCount;
261
        DebugOut.Analog[29] = pitchOffset;
262
 
263
        return pitchCount;
264
}
265
 
266
 
267
/*
268
 * Berechnet den Korrekturwert für die Höhenregelung
269
 */
270
int altitudeController( void ) {
271
 
272
        int register    n = 0;
273
        int register    error;
274
 
275
        if( ( state == STATE_ACTIVE ) && !Notlandung ) {
276
 
277
                // Fehlerwert für Regler ermitteln
278
                error = airPressure - pressureOffset;
279
 
280
                // Proportionalanteil
281
                n = ( PARAM_ALT_P * error ) / 4;        // dividiert durch ( 16 / STICK_GAIN ) = 16 / 4 = 4
282
 
283
                // Integralanteil
284
                altIntegral += ( PARAM_ALT_I * error ) / 4;
285
 
286
                // Integral begrenzen
287
                if( altIntegral > PARAM_ALT_INT_MAX )
288
                        altIntegral = PARAM_ALT_INT_MAX;
289
                else if( altIntegral < -PARAM_ALT_INT_MAX )
290
                        altIntegral = -PARAM_ALT_INT_MAX;
291
 
292
                n += altIntegral / 1000;                // 4 * Reglerfrequenz = 4 * 500Hz = 1000
293
 
294
                // Differenzialanteil
295
                n           += ( PARAM_ALT_D * ( airPressure - lastAirPressure ) ) / 2;
296
                lastAirPressure = airPressure;
297
 
298
                // ACC-Z-Integral zur Dämpfung einbeziehen
299
                temp = ( ( ( Mess_Integral_Hoch / 128 ) - accZOffset ) * (signed long) PARAM_ALT_ACC ) / 32;
300
 
301
                // Dämpfung limitieren
302
                if( temp > ( 70 << STICK_GAIN_SHIFT ) )
303
                        temp = 70 << STICK_GAIN_SHIFT;
304
                else if( temp < -( 70 << STICK_GAIN_SHIFT ) )
305
                        temp = -( 70 << STICK_GAIN_SHIFT );
306
 
307
                n += temp;
308
 
309
                // Verstärkung des Fehlerwertes zur Anpassung des Gewichtes
310
                n = n * PARAM_ALT_GAIN / 10;
311
 
312
                int altMax = PARAM_ALT_MAX << STICK_GAIN_SHIFT;
313
 
314
                // Limitierung des Korrekturwertes
315
                if( n > altMax )
316
                        n = altMax;
317
                else if( n < -altMax )
318
                        n = -altMax;
319
 
320
                // Korrekturwert glätten
321
                n     = ( n + 15 * lastN ) / 16;
322
                lastN = n;
323
        }
324
 
325
//      DebugOut.Analog[28] = altIntegral;
326
//      DebugOut.Analog[27] = n;
327
 
328
        return n;
329
}