Subversion Repositories FlightCtrl

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1233 thjac 1
/* pitch_md.c
2
 *
3
 * Copyright 2009 Thomas Jachmann
4
 *
5
 * Die in dieser Quelldatei enthaltenen Algorithmen ermöglichen eine MD-ähnliche Pitch-Steuerung
6
 * für den MK.
7
 */
8
 
9
#include "main.h"
10
#include "parameter.h"
11
#include "fc.h"
12
#include "pitch.h"
13
#include "altcon.h"
14
 
15
 
16
#define STATE_INITIALIZE                0x01                    // Anfangszustand nach Einschalten der Motoren
17
#define STATE_SETUP                     0x02                    // Ermittlung von PARAM_PITCH_MD_HOVER
18
#define STATE_SETUP_HOVER               0x03                    // Konfiguration pitchHover
19
#define STATE_SETUP_STICK_DELTA         0x04                    // Konfiguration pitchNeutralDiff
20
#define STATE_SETUP_STICK_DELTA1        0x05
21
#define STATE_BEGIN                     0x06                    // Anfangszustand für Flugbetrieb
22
#define STATE_BEGIN1                    0x07                    // Anfangszustand für Flugbetrieb
23
#define STATE_READY0                    0x08                    // Manuelle Kontrolle
24
#define STATE_READY                     0x09                    // Manuelle Kontrolle
25
#define STATE_READY1                    0x0a
26
#define STATE_WAIT                      0x0b                    // Warten auf Einschalten der Höhenregelung
27
#define STATE_ACTIVATING                0x0c                    // Aktivierung der Höhenregelung
28
#define STATE_ACTIVE                    0x0d                    // Höhenregelung ist aktiv
29
#define STATE_RESTART                   0x0e                    // Neustart
30
 
31
static int      stickValue              = 0;                    // Aktueller Stick-Wert
32
static int      lastStickValue          = 0;                    // Vorheriger Stick-Wert
33
static int      actualPitchCount = 0;                           // Soll-Pitch-Wert
34
static int      targetPitchCount = 0;                           // Ist-Pitch-Wert
35
static int      pitchOffset;                                    // Aktueller Grundgaswert in Neutralstellung
36
static char     state;                                          // Zustand
37
static int      timer;
38
static int      delay                   = 0;
39
static int      delayCounter            = 0;
40
static int      peakPitchCount;
41
 
42
unsigned char   pitchHover              = 0;                    // Standgaswert
43
unsigned char   pitchNeutralDiffMD      = 0;                    // Suffix MD später entfernen
44
 
45
 
46
void pitch_md_init( void ) {
47
 
48
    pitchHover         = eeprom_read_byte( &EEPromArray[ EEPROM_ADR_PITCH_MD_HOVER ] );
49
    pitchNeutralDiffMD = eeprom_read_byte( &EEPromArray[ EEPROM_ADR_PITCH_NEUTRAL_DIFF ] );
50
}
51
 
52
 
53
/*
54
 * Berechnet den aktuellen Pitch-Wert für die Regelung
55
 *
56
 * Funktionsweise:
57
 *
58
 * 1. Einmalig muß man das Standgas kalibrieren. Standgas ist ein neuer Parameter.
59
 *    Dies tut man durch Betätigen des Roll-Sticks nach links (Vollausschlag) und
60
 *    Starten der Motoren. Nun gibt man soviel Gas (in der oberen Hälfte des Stick-Bereichs) wie
61
 *    der MK gerade noch stabil auf dem Boden steht. Man hält diese Stick-Position solange, bis ein
62
 *    Signal ertönt. Damit wurde der Gaswert als Standgasparameter übernommen und im EEProm dauerhaft gespeichert.
63
 *    Diese Kalibrierung muß mit vollem Akku und nach jeder Gewichtsänderung des MK einmal durchgeführt werden.
64
 *
65
 * 2. Für den Flug startet man die Motoren und läßt den Stick los. Die Motoren laufen im Leerlaufgas.
66
 *
67
 * 3. Nun schaltet man auf Standgas durch kurzes Antippen des Sticks nach oben. Die Motoren beschleunigen langsam
68
 *    bis zum Erreichen des zuvor kalibriertes Standgaswertes.
69
 *
70
 * 4. Nun hebt man wie gewohnt ab. Hierzu hat man den oberen Stick-Bereich zur Verfügung. Da der Grundgaswert
71
 *    bei Mittelstellung jetzt knapp unterhalb des Schwebegaswertes liegt, kann man im Flug einfach die Höhe halten,
72
 *    indem man den Stick in Mittelstellung bewegt. Nach kurzer Zeit (quittiert mit einem Piep) wird die automatische
73
 *    Höhenregelung aktiviert und solange gehalten, bis man den Stick wieder bewegt.
74
 *
75
 * 5. Nach der Landung drückt man den Stick ganz nach unten, bis ein Signal ertönt. Jetzt laufen die Motoren
76
 *    wieder im Leerlaufgas. Man kann nun neu Starten (ab Punkt 3) oder die Motoren ausschalten.
77
 */
78
int pitch_md_value( void ) {
79
 
80
        int register rawStickValue = PPM_in[ EE_Parameter.Kanalbelegung[ K_GAS ] ] - pitch_initialStickValue();
81
 
82
        // Sind die Motoren eingeschaltet?
83
        if( MotorenEin ) {
84
 
85
                // Vorigen Stick-Wert merken
86
                lastStickValue = stickValue;
87
 
88
                /* StickValue exponentiell angleichen, da ausgehend von der Neutralstellung
89
                 * nur jeweils die halbe Auflösung nach oben und unten zur Verfügung steht. Bei einer
90
                 * Multiplikation mit 2 ließe sich das Gas im Schwebebereich nicht fein genug einstellen. */
91
                if( rawStickValue > 0 ) {
92
                        stickValue = rawStickValue + ( ( (long) rawStickValue * (long) rawStickValue ) / 150L );
93
                } else {
94
                        stickValue = rawStickValue - ( ( (long) rawStickValue * (long) rawStickValue ) / 150L );
95
                }
96
 
97
                /* Aktuellen Pitch-Wert berechnen. Der Wert ergibt sich aus dem Pitch-Offset
98
                 * zuzüglich dem Stick-Wert. */
99
                targetPitchCount = stickValue + pitchOffset;
100
 
101
                switch( state ) {
102
 
103
                        /* Entscheidet über Flugbetrieb oder Setup-Betrieb. Für den Setup-Betrieb
104
                         * muß beim Einschalten der Motoren gleichzeitig der Roll-Stick ganz
105
                         * betätigt werden. Es gilt:
106
                         *
107
                         * Roll-Stick links:  Einstellen des Gas-Stick-Deltas
108
                         * Roll-Stick rechts: Einstellen des Schwebegases
109
                         */
110
                        case STATE_INITIALIZE:
111
 
112
                                if( PPM_in[ EE_Parameter.Kanalbelegung[ K_ROLL ] ] > 70 ) {
113
                                        state = STATE_SETUP_HOVER;
114
 
115
                                        // Signalisieren
116
                                        beeptime = 500;
117
 
118
                                } else if( PPM_in[ EE_Parameter.Kanalbelegung[ K_ROLL ] ] < -70 ) {
119
                                        state = STATE_SETUP_STICK_DELTA;
120
 
121
                                        // Signalisieren
122
                                        beeptime = 500;
123
 
124
                                } else {
125
                                        state = STATE_RESTART;
126
                                }
127
                                break;
128
 
129
                        /* Erlaubt die Ermittlung des Parameters pitchHover. Hierzu wird soviel Gas
130
                         * gegeben, bis der MK kurz vor dem Abheben ist, jedoch noch stabil steht. Um den
131
                         * Gaswert dauerhaft zu speichern, muß der Stick an der Position verweilen, bis
132
                         * der Summer die Übernahme akustisch quittiert. Dann müssen die Motoren wieder
133
                         * ausgeschaltet werden, da dieser Modus nicht für den Flug vorgesehen ist.
134
                         */            
135
                        case STATE_SETUP_HOVER:
136
 
137
                                // Im Setup-Modus soll das Gas nicht träge reagieren
138
                                actualPitchCount = targetPitchCount;
139
 
140
                                if( rawStickValue < 10 || abs( stickValue - lastStickValue ) > 1 ) {
141
                                        timer = PARAM_TIMER_2S;
142
                                }
143
 
144
                                /* Der Stick befindet sich eindeutig in der oberen Hälfte und wurde
145
                                 * seit dem letzten Zyklus nicht bewegt. */
146
                                else {
147
                                        timer--;
148
 
149
                                        /* Die Verweilzeit ist abgelaufen und der aktuelle Pitch-Wert
150
                                         * entspricht nicht dem bereits gespeicherten Wert. */
151
                                        if( !timer && ( pitchHover != actualPitchCount ) ) {
152
 
153
                                                // Aktuellen Pitch-Wert in Konfiguration übernehmen
154
                                                pitchHover = actualPitchCount;
155
 
156
                                                // Konfiguration dauerhaft speichern
157
                                                eeprom_write_byte( &EEPromArray[ EEPROM_ADR_PITCH_MD_HOVER ], pitchHover );
158
 
159
                                                // Signalisieren
160
                                                beeptime = 500;
161
                                        }
162
                                }
163
                                break;
164
 
165
                        /* Der Stick-Deltawert kann hier konfiguriert werden. Ein Betätigen des Roll-Sticks nach links
166
                         * erhöht den Deltawert um 1, ein Betätigen nach rechts veringert den Wert um 1. Der eingestellte
167
                         * Wert kann mit dem Gas-Stick getestet werden, indem dieser in den oberen Bereich bewegt und dann
168
                         * losgelassen wird. Ertönt dabei ein Signal, wurde die Bewegung erkannt. Es ist dann der richtige
169
                         * Wert gefunden, wenn das Signal beim Loslassen des Gas-Sticks ertönt, beim gesteuerten Bewegen nach
170
                         * unten jedoch nicht. Durch Ausschalten der Motoren (diese laufen während der Konfiguration nicht
171
                         * wirklich) wird der Konfigurationsmodus beendet.
172
                         */
173
                        case STATE_SETUP_STICK_DELTA:
174
                                if( stickValue < PARAM_PITCH_STICK_THRESHOLD &&
175
                                    abs( PPM_in[ EE_Parameter.Kanalbelegung[ K_ROLL ] ] ) < PARAM_PITCH_STICK_THRESHOLD ) {
176
                                        state = STATE_SETUP_STICK_DELTA1;
177
                                }
178
 
179
                                // Im Setup immer mit Leerlaufgas
180
                                targetPitchCount = 0;
181
 
182
                                break;
183
 
184
                        case STATE_SETUP_STICK_DELTA1:
185
 
186
                                // Roll-Stick nach links erhöht den Deltawert
187
                                if( PPM_in[ EE_Parameter.Kanalbelegung[ K_ROLL ] ] < -20 ) {
188
                                        if( pitchNeutralDiffMD < 20 ) {
189
                                                pitchNeutralDiffMD++;
190
 
191
                                                // Konfiguration dauerhaft speichern
192
                                                eeprom_write_byte( &EEPromArray[ EEPROM_ADR_PITCH_NEUTRAL_DIFF ], pitchNeutralDiffMD );
193
 
194
                                                // Signalisieren
195
                                                beeptime = 500;
196
 
197
                                                state    = STATE_SETUP_STICK_DELTA;
198
                                        }
199
                                }
200
 
201
                                // Roll-Stick nach rechts verringert den Deltawert
202
                                if( PPM_in[ EE_Parameter.Kanalbelegung[ K_ROLL ] ] > 20 ) {
203
                                        if( pitchNeutralDiffMD > 0 ) {
204
                                                pitchNeutralDiffMD--;
205
 
206
                                                // Konfiguration dauerhaft speichern
207
                                                eeprom_write_byte( &EEPromArray[ EEPROM_ADR_PITCH_NEUTRAL_DIFF ], pitchNeutralDiffMD );
208
 
209
                                                // Signalisieren
210
                                                beeptime = 500;
211
 
212
                                                state    = STATE_SETUP_STICK_DELTA;
213
                                        }
214
                                }
215
 
216
                                if( ( lastStickValue > PARAM_PITCH_STICK_THRESHOLD ) &&
217
                                    ( lastStickValue - stickValue >= pitchNeutralDiffMD ) ) {
218
 
219
                                        state    = STATE_SETUP_STICK_DELTA;
220
 
221
                                        // Signalisieren
222
                                        beeptime = 500;
223
                                }
224
 
225
                                // Im Setup immer mit Leerlaufgas
226
                                targetPitchCount = 0;
227
 
228
                                break;
229
 
230
                        /* In diesem Zustand steht der MK am Boden und die Motoren laufen auf Leerlaufgas. Ein
231
                         * kurzes Auslenken des Sticks nach oben schaltet in das Standgas über.
232
                         */
233
                        case STATE_BEGIN:
234
 
235
                                // Stick ist oberhalb der Neutralstellung
236
                                if( rawStickValue > PARAM_PITCH_STICK_THRESHOLD ) {
237
                                        pitchOffset = pitchHover;
238
 
239
                                        /* In diesem Zustand darf Schwebegas nicht überschritten werden, damit
240
                                         * der MK nicht aus diesem Status heraus abhebt.
241
                                         */
242
                                        if( targetPitchCount > pitchHover ) {
243
                                                targetPitchCount = pitchHover;
244
                                        }
245
 
246
                                // Erst im Status weitergehen, wenn Stick nicht mehr oberhalb der Neutralstellung
247
                                } else if( pitchOffset == pitchHover ) {
248
                                        state = STATE_BEGIN1;
249
                                }
250
                                break;
251
 
252
                        // MK soll erst abheben, weil sonst die Höhenregelung am Boden schon greift
253
                        case STATE_BEGIN1:
254
 
255
                                // Jetzt kann abgehoben werden
256
                                if( rawStickValue > PARAM_PITCH_STICK_THRESHOLD ) {
257
 
258
                                        // Begrenzung der Pitch-Beschleunigung nach dem Start
259
                                        delay = PARAM_PITCH_MD_DELAY1;
260
 
261
                                        state = STATE_READY0;
262
 
263
                                // Knüppel unterhalb der Neutralstellung bewirkt einen sofortigen Neustart
264
                                } else if( rawStickValue < -PARAM_PITCH_STICK_THRESHOLD ) {
265
 
266
                                        state = STATE_RESTART;
267
                                }
268
                                break;
269
 
270
                        /* Die Motoren laufen jetzt mindestens mit Standgas. Der MK ist bereit zum Abheben.
271
                         */
272
                        case STATE_READY0:
273
 
274
                                /* Wenn der Gashebel ganz unten steht, Timer für Restart der Pitch-Regelung
275
                                 * starten. Hierfür wird die Variable pitchNeutralTimer verwendet. */
276
                                if( PPM_in[ EE_Parameter.Kanalbelegung[ K_GAS ] ] > 35 - 120 ) {
277
                                        timer = PITCH_MIN2_TIMER;
278
                                } else {
279
                                        timer--;
280
 
281
                                        /* Gashebel steht seit PITCH_MIN2_TIMER ganz unten; jetzt erfolgt die Initialisierung. */
282
                                        if( !timer ) {
283
                                                state = STATE_RESTART;
284
                                        }
285
                                }
286
 
287
                                /* Übergang in den höhengeregelten Flug durch:
288
                                 * 1. Schnelles Bewegen des Sticks in Richtung Mittelstellung
289
                                 *    oder
290
                                 * 2. langsames Bewegen des Sticks in Mittelstellung */
291
                                if( ( ( lastStickValue > PARAM_PITCH_STICK_THRESHOLD ) &&
292
                                      ( lastStickValue - stickValue >= pitchNeutralDiffMD ) ) ||
293
                                    ( ( lastStickValue < PARAM_PITCH_STICK_THRESHOLD ) &&
294
                                        PARAM_PITCH_SOFT_ACTIVATING ) ) {
295
 
296
                                        // Aktuelle Höhe festhalten (aktiviert noch nicht den Regler)
297
                                        altcon_lock();
298
 
299
                                        // Höhe vorübergehend merken und beibehalten
300
                                        peakPitchCount = lastStickValue;
301
 
302
                                        state          = STATE_READY1;
303
                                        timer          = PITCH_NEUTRAL_TIMER;
304
                                        delay          = PARAM_PITCH_MD_DELAY2;
305
                                }
306
 
307
                                break;
308
 
309
                        case STATE_READY:
310
 
311
                                /* Wenn der Gashebel ganz unten steht, Timer für Restart der Pitch-Regelung
312
                                 * starten. Hierfür wird die Variable pitchNeutralTimer verwendet. */
313
                                if( PPM_in[ EE_Parameter.Kanalbelegung[ K_GAS ] ] > 35 - 120 ) {
314
                                        timer = PITCH_MIN2_TIMER;
315
                                } else {
316
                                        timer--;
317
 
318
                                        /* Gashebel steht seit PITCH_MIN2_TIMER ganz unten; jetzt erfolgt die Initialisierung. */
319
                                        if( !timer ) {
320
                                                state = STATE_RESTART;
321
                                        }
322
                                }
323
 
324
                                // Stick ist innerhalb der Neutralstellung
325
                                if( abs( rawStickValue ) < PARAM_PITCH_STICK_THRESHOLD ) {
326
 
327
                                        // Aktuelle Höhe festhalten (aktiviert noch nicht den Regler)
328
                                        altcon_lock();
329
 
330
                                        // Timer neu setzen
331
                                        timer = PITCH_NEUTRAL_TIMER;
332
 
333
                                        state = STATE_WAIT;
334
                                }
335
                                break;
336
 
337
                        /* Hier wird die Zeit gemessen, in der der Stick nach dem Loslassen
338
                         * bis zur Neutralstellung benötigt. Bei Überschreiten der Zeit
339
                         * wird die Höhenregelung nicht aktiviert.
340
                         */
341
                        case STATE_READY1:
342
 
343
                                // Gas wird konstant gehalten
344
                                targetPitchCount = peakPitchCount + pitchOffset;
345
 
346
                                timer--;
347
 
348
                                /* Läuft der Timer ab, bevor der Stick die Neutralstellung erreicht,
349
                                 * wird die Aktion nicht als "schnelles Bewegen in Neutralstellung"
350
                                 * gedeutet. */
351
 
352
                                if( !timer ) {
353
                                        state = STATE_READY0;
354
                                }
355
 
356
                                // Ist die Neutralstellung erreicht?
357
                                if( rawStickValue < PARAM_PITCH_STICK_THRESHOLD ) {
358
 
359
                                        pitchOffset = targetPitchCount;
360
 
361
                                        // Aktivierung des Höhenreglers mit der zuvor gemerkten Sollhöhe
362
                                        altcon_start();
363
 
364
                                        state = STATE_ACTIVE;
365
                                }
366
                                break;
367
 
368
                        /* Der Stick ist in den für die Neutralstellung gültigen Wertebereich
369
                         * gelangt. Nun darf innerhalb einer bestimmten Zeit keine Stick-Bewegung
370
                         * erfolgen, um die automatische Höhenregelung zu aktivieren. */
371
                        case STATE_WAIT:
372
 
373
                                /* Stick ist innerhalb der Neutralstellung und
374
                                   Stick-Differenzial ist < 2 */
375
                                if( abs( rawStickValue ) < PARAM_PITCH_STICK_THRESHOLD &&
376
                                    abs( stickValue - lastStickValue ) < 2 ) {
377
 
378
                                        timer--;
379
 
380
                                        if( !timer ) {
381
                                                state = STATE_ACTIVATING;
382
                                        }
383
 
384
                                // Aktivierungskriterium nicht erfüllt, zurück in INACTIVE
385
                                } else {
386
                                        state = STATE_READY;
387
                                }
388
                                break;
389
 
390
                        /* Die automatische Höhenregelung wird jetzt aktiviert.
391
                         */
392
                        case STATE_ACTIVATING:
393
 
394
                                /* Nach Aktivierung der Höhenregelung soll sich der Gaswert nicht mehr
395
                                 * ändern. */
396
                                actualPitchCount = targetPitchCount;
397
                                pitchOffset      = targetPitchCount;
398
 
399
                                // Aktivierung des Höhenreglers mit der zuvor gemerkten Sollhöhe
400
                                altcon_start();
401
 
402
                                state = STATE_ACTIVE;
403
                                break;
404
 
405
                        /* Die automatische Höhenregelung ist aktiv. */                
406
                        case STATE_ACTIVE:
407
 
408
                                targetPitchCount = pitchOffset;
409
 
410
                                // Stick ist außerhalb der Neutralstellung
411
                                if( abs( rawStickValue ) > PARAM_PITCH_STICK_THRESHOLD ) {
412
 
413
                                        // Höhenregler deaktivieren
414
                                        altcon_stop();
415
 
416
                                        pitchOffset     -= altcon_avgerror() / 4;
417
                                        targetPitchCount = stickValue + pitchOffset;
418
                                        state            = STATE_READY;
419
                                }
420
                                break;
421
 
422
                        /* Neustart nach dem Flug oder vor Start. */
423
                        case STATE_RESTART:
424
 
425
                                // Begrenzung der Pitch-Beschleunigung am Boden
426
                                delay = PARAM_PITCH_MD_DELAY0;
427
 
428
                                pitchOffset      = 0;
429
                                targetPitchCount = 0;
430
 
431
                                // Folgezustand
432
                                state = STATE_BEGIN;
433
 
434
                                break;
435
                }
436
 
437
        // Motoren sind aus
438
        } else {
439
 
440
                /* Nach dem Einschalten der Motoren wird pitchOffset auf PARAM_PITCH_OVER gesetzt.
441
                 */
442
                actualPitchCount = 0;
443
                targetPitchCount = 0;
444
                pitchOffset      = 0;
445
                stickValue       = 0;
446
                state            = STATE_INITIALIZE;
447
        }
448
 
449
        /* Durch die Sollwertvorgabe kann hier eine einstellbare Trägheit auf dem Pitch-Wert
450
         * abgebildet werden. */
451
        int pitchDelta = targetPitchCount - actualPitchCount;
452
 
453
        if( pitchDelta > delay )
454
                pitchDelta = delay;
455
        if( pitchDelta < -delay )
456
                pitchDelta = -delay;
457
 
458
        if( !delayCounter ) {
459
                actualPitchCount += pitchDelta;
460
                delayCounter      = 5;
461
        }
462
 
463
        delayCounter--;
464
 
465
        if( actualPitchCount < 0 )
466
                actualPitchCount = 0;
467
 
468
        DebugOut.Analog[25] = pitchOffset;
469
        DebugOut.Analog[26] = stickValue;
470
 
471
        return actualPitchCount;
472
}