Subversion Repositories FlightCtrl

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1775 - 1
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2
// + Copyright (c) 04.2007 Holger Buss
3
// + Nur für den privaten Gebrauch
4
// + www.MikroKopter.com
5
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6
// + Es gilt für das gesamte Projekt (Hardware, Software, Binärfiles, Sourcecode und Dokumentation),
7
// + dass eine Nutzung (auch auszugsweise) nur für den privaten (nicht-kommerziellen) Gebrauch zulässig ist.
8
// + Sollten direkte oder indirekte kommerzielle Absichten verfolgt werden, ist mit uns (info@mikrokopter.de) Kontakt
9
// + bzgl. der Nutzungsbedingungen aufzunehmen.
10
// + Eine kommerzielle Nutzung ist z.B.Verkauf von MikroKoptern, Bestückung und Verkauf von Platinen oder Bausätzen,
11
// + Verkauf von Luftbildaufnahmen, usw.
12
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
13
// + Werden Teile des Quellcodes (mit oder ohne Modifikation) weiterverwendet oder veröffentlicht,
14
// + unterliegen sie auch diesen Nutzungsbedingungen und diese Nutzungsbedingungen incl. Copyright müssen dann beiliegen
15
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16
// + Sollte die Software (auch auszugesweise) oder sonstige Informationen des MikroKopter-Projekts
17
// + auf anderen Webseiten oder sonstigen Medien veröffentlicht werden, muss unsere Webseite "http://www.mikrokopter.de"
18
// + eindeutig als Ursprung verlinkt werden
19
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
20
// + Keine Gewähr auf Fehlerfreiheit, Vollständigkeit oder Funktion
21
// + Benutzung auf eigene Gefahr
22
// + Wir übernehmen keinerlei Haftung für direkte oder indirekte Personen- oder Sachschäden
23
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
24
// + Die Portierung der Software (oder Teile davon) auf andere Systeme (ausser der Hardware von www.mikrokopter.de) ist nur
25
// + mit unserer Zustimmung zulässig
26
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
27
// + Die Funktion printf_P() unterliegt ihrer eigenen Lizenz und ist hiervon nicht betroffen
28
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
29
// + Redistributions of source code (with or without modifications) must retain the above copyright notice,
30
// + this list of conditions and the following disclaimer.
31
// +   * Neither the name of the copyright holders nor the names of contributors may be used to endorse or promote products derived
32
// +     from this software without specific prior written permission.
33
// +   * The use of this project (hardware, software, binary files, sources and documentation) is only permittet
34
// +     for non-commercial use (directly or indirectly)
35
// +     Commercial use (for excample: selling of MikroKopters, selling of PCBs, assembly, ...) is only permitted
36
// +     with our written permission
37
// +   * If sources or documentations are redistributet on other webpages, out webpage (http://www.MikroKopter.de) must be
38
// +     clearly linked as origin
39
// +   * porting to systems other than hardware from www.mikrokopter.de is not allowed
40
// +  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
41
// +  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
// +  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43
// +  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
44
// +  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
45
// +  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
46
// +  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
47
// +  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN// +  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48
// +  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49
// +  POSSIBILITY OF SUCH DAMAGE.
50
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
51
 
52
/************************************************************************/
53
/* Flight Attitude                                                      */
54
/************************************************************************/
55
 
56
#include <stdlib.h>
57
#include <avr/io.h>
58
 
59
#include "attitude.h"
60
#include "dongfangMath.h"
61
 
62
// For scope debugging only!
63
#include "rc.h"
64
 
65
// where our main data flow comes from.
66
#include "analog.h"
67
 
68
#include "configuration.h"
69
 
70
#include "output.h"
71
 
72
// Some calculations are performed depending on some stick related things.
73
#include "controlMixer.h"
74
 
75
// For Servo_On / Off
76
// #include "timer2.h"
77
 
78
#ifdef USE_MK3MAG
79
#include "mk3mag.h"
80
#include "gps.h"
81
#endif
82
#define CHECK_MIN_MAX(value, min, max) {if(value < min) value = min; else if(value > max) value = max;}
83
 
84
/*
85
 * Gyro readings, as read from the analog module. It would have been nice to flow
86
 * them around between the different calculations as a struct or array (doing
87
 * things functionally without side effects) but this is shorter and probably
88
 * faster too.
89
 * The variables are overwritten at each attitude calculation invocation - the values
90
 * are not preserved or reused.
91
 */
92
int16_t rate_ATT[2], yawRate;
93
 
94
// With different (less) filtering
95
int16_t rate_PID[2];
96
int16_t differential[2];
97
 
98
/*
99
 * Gyro readings, after performing "axis coupling" - that is, the transfomation
100
 * of rotation rates from the airframe-local coordinate system to a ground-fixed
101
 * coordinate system. If axis copling is disabled, the gyro readings will be
102
 * copied into these directly.
103
 * These are global for the same pragmatic reason as with the gyro readings.
104
 * The variables are overwritten at each attitude calculation invocation - the values
105
 * are not preserved or reused.
106
 */
107
int16_t ACRate[2], ACYawRate;
108
 
109
/*
110
 * Gyro integrals. These are the rotation angles of the airframe compared to the
111
 * horizontal plane, yaw relative to yaw at start.
112
 */
113
int32_t angle[2], yawAngleDiff;
114
 
115
int readingHeight = 0;
116
 
117
// compass course
118
int16_t compassHeading       = -1; // negative angle indicates invalid data.
119
int16_t compassCourse        = -1;
120
int16_t compassOffCourse     = 0;
121
uint16_t updateCompassCourse = 0;
122
uint8_t compassCalState      = 0;
123
uint16_t badCompassHeading = 500;
124
int32_t yawGyroHeading; // Yaw Gyro Integral supported by compass
125
int16_t yawGyroDrift;
126
 
127
#define PITCHROLLOVER180 (GYRO_DEG_FACTOR_PITCHROLL * 180L)
128
#define PITCHROLLOVER360 (GYRO_DEG_FACTOR_PITCHROLL * 360L)
129
#define YAWOVER360       (GYRO_DEG_FACTOR_YAW * 360L)
130
 
131
int16_t correctionSum[2] = {0,0};
132
 
133
// For NaviCTRL use.
134
int16_t averageAcc[2] = {0,0}, averageAccCount = 0;
135
 
136
/*
137
 * Experiment: Compensating for dynamic-induced gyro biasing.
138
 */
139
int16_t driftComp[2] = {0,0}, driftCompYaw = 0;
140
// int16_t savedDynamicOffsetPitch = 0, savedDynamicOffsetRoll = 0;
141
// int32_t dynamicCalPitch, dynamicCalRoll, dynamicCalYaw;
142
// int16_t dynamicCalCount;
143
 
144
/************************************************************************
145
 * Set inclination angles from the acc. sensor data.                    
146
 * If acc. sensors are not used, set to zero.                          
147
 * TODO: One could use inverse sine to calculate the angles more        
148
 * accurately, but since: 1) the angles are rather small at times when
149
 * it makes sense to set the integrals (standing on ground, or flying at  
150
 * constant speed, and 2) at small angles a, sin(a) ~= constant * a,    
151
 * it is hardly worth the trouble.                                      
152
 ************************************************************************/
153
 
154
int32_t getAngleEstimateFromAcc(uint8_t axis) {
155
  return GYRO_ACC_FACTOR * (int32_t)filteredAcc[axis];
156
}
157
 
158
void setStaticAttitudeAngles(void) {
159
#ifdef ATTITUDE_USE_ACC_SENSORS
160
  angle[PITCH] = getAngleEstimateFromAcc(PITCH);
161
  angle[ROLL] = getAngleEstimateFromAcc(ROLL);
162
#else
163
  angle[PITCH] = angle[ROLL] = 0;
164
#endif
165
}
166
 
167
/************************************************************************
168
 * Neutral Readings                                                    
169
 ************************************************************************/
170
void attitude_setNeutral(void) {
171
  // Servo_Off(); // disable servo output. TODO: Why bother? The servos are going to make a jerk anyway.
172
  dynamicParams.AxisCoupling1 = dynamicParams.AxisCoupling2 = 0;
173
 
174
  driftComp[PITCH] = driftComp[ROLL] = yawGyroDrift = driftCompYaw = 0;
175
  correctionSum[PITCH] = correctionSum[ROLL] = 0;
176
 
177
  // Calibrate hardware.
178
  analog_calibrate();
179
 
180
  // reset gyro readings
181
  // rate_ATT[PITCH] = rate_ATT[ROLL] = yawRate = 0;
182
 
183
  // reset gyro integrals to acc guessing
184
  setStaticAttitudeAngles();
185
  yawAngleDiff = 0;
186
 
187
  // update compass course to current heading
188
  compassCourse = compassHeading;
189
 
190
  // Inititialize YawGyroIntegral value with current compass heading
191
  yawGyroHeading = (int32_t)compassHeading * GYRO_DEG_FACTOR_YAW;
192
 
193
  // Servo_On(); //enable servo output
194
}
195
 
196
/************************************************************************
197
 * Get sensor data from the analog module, and release the ADC          
198
 * TODO: Ultimately, the analog module could do this (instead of dumping
199
 * the values into variables).
200
 * The rate variable end up in a range of about [-1024, 1023].
201
 *************************************************************************/
202
void getAnalogData(void) {
203
  uint8_t axis;
204
 
205
  for (axis=PITCH; axis <=ROLL; axis++) {
206
    rate_PID[axis]     = (gyro_PID[axis] + driftComp[axis]) / HIRES_GYRO_INTEGRATION_FACTOR;
207
    rate_ATT[axis]     = (gyro_ATT[axis] + driftComp[axis]) / HIRES_GYRO_INTEGRATION_FACTOR;
208
    differential[axis] = gyroD[axis];
209
    averageAcc[axis]  += acc[axis];
210
  }
211
 
212
  averageAccCount++;
213
  yawRate = yawGyro + driftCompYaw;
214
 
215
  // We are done reading variables from the analog module.
216
  // Interrupt-driven sensor reading may restart.
217
  analogDataReady = 0;
218
  analog_start();
219
}
220
 
221
/*
222
 * This is the standard flight-style coordinate system transformation
223
 * (from airframe-local axes to a ground-based system). For some reason
224
 * the MK uses a left-hand coordinate system. The tranformation has been
225
 * changed accordingly.
226
 */
227
void trigAxisCoupling(void) {
228
  int16_t cospitch = int_cos(angle[PITCH]);
229
  int16_t cosroll =  int_cos(angle[ROLL]);
230
  int16_t sinroll =  int_sin(angle[ROLL]);
231
  int16_t tanpitch = int_tan(angle[PITCH]);
232
#define ANTIOVF 512
233
  ACRate[PITCH] =                 ((int32_t) rate_ATT[PITCH] * cosroll - (int32_t)yawRate * sinroll) / (int32_t)MATH_UNIT_FACTOR;
234
  ACRate[ROLL] = rate_ATT[ROLL] + (((int32_t)rate_ATT[PITCH] * sinroll / ANTIOVF * tanpitch + (int32_t)yawRate * int_cos(angle[ROLL]) / ANTIOVF * tanpitch) / ((int32_t)MATH_UNIT_FACTOR / ANTIOVF * MATH_UNIT_FACTOR));
235
  ACYawRate =                     ((int32_t) rate_ATT[PITCH] * sinroll) / cospitch + ((int32_t)yawRate * cosroll) / cospitch;
236
}
237
 
238
// 480 usec with axis coupling - almost no time without.
239
void integrate(void) {
240
  // First, perform axis coupling. If disabled xxxRate is just copied to ACxxxRate.
241
  uint8_t axis;
242
  if(!looping && (staticParams.GlobalConfig & CFG_AXIS_COUPLING_ACTIVE)) {
243
    // The rotary rate limiter bit is abused for selecting axis coupling algorithm instead.
244
    trigAxisCoupling();
245
  } else {
246
    ACRate[PITCH] = rate_ATT[PITCH];
247
    ACRate[ROLL]  = rate_ATT[ROLL];
248
    ACYawRate     = yawRate;
249
  }
250
 
251
  /*
252
   * Yaw
253
   * Calculate yaw gyro integral (~ to rotation angle)
254
   * Limit yawGyroHeading proportional to 0 deg to 360 deg
255
   */
256
  yawGyroHeading += ACYawRate;
257
  yawAngleDiff += yawRate;
258
 
259
  if(yawGyroHeading >= YAWOVER360) {
260
    yawGyroHeading -= YAWOVER360;  // 360 deg. wrap
261
  } else if(yawGyroHeading < 0) {
262
    yawGyroHeading += YAWOVER360;
263
  }
264
 
265
  /*
266
   * Pitch axis integration and range boundary wrap.
267
   */
268
  for (axis=PITCH; axis<=ROLL; axis++) {
269
    angle[axis] += ACRate[axis];
270
    if(angle[axis] > PITCHROLLOVER180) {
271
      angle[axis] -= PITCHROLLOVER360;
272
    } else if (angle[axis] <= -PITCHROLLOVER180) {
273
      angle[axis] += PITCHROLLOVER360;
274
    }
275
  }
276
}
277
 
278
/************************************************************************
279
 * A kind of 0'th order integral correction, that corrects the integrals
280
 * directly. This is the "gyroAccFactor" stuff in the original code.
281
 * There is (there) also a drift compensation
282
 * - it corrects the differential of the integral = the gyro offsets.
283
 * That should only be necessary with drifty gyros like ENC-03.
284
 ************************************************************************/
285
void correctIntegralsByAcc0thOrder(void) {
286
  // TODO: Consider changing this to: Only correct when integrals are less than ...., or only correct when angular velocities
287
  // are less than ....., or reintroduce Kalman.
288
  // Well actually the Z axis acc. check is not so silly.
289
  uint8_t axis;
290
  int32_t correction;
291
  if(!looping && acc[Z] >= -dynamicParams.UserParams[7] && acc[Z] <= dynamicParams.UserParams[7]) {
292
    DebugOut.Digital[0] |= DEBUG_ACC0THORDER;
293
 
294
    uint8_t permilleAcc = staticParams.GyroAccFactor; // NOTE!!! The meaning of this value has changed!!
295
    uint8_t debugFullWeight = 1;
296
    int32_t accDerived;
297
 
298
    if((maxControl[PITCH] > 64) || (maxControl[ROLL] > 64)) { // reduce effect during stick commands
299
      permilleAcc /= 2;
300
      debugFullWeight = 0;
301
    }
302
 
303
    if(abs(controlYaw) > 25) { // reduce further if yaw stick is active
304
      permilleAcc /= 2;
305
      debugFullWeight = 0;
306
    }
307
 
308
    /*
309
     * Add to each sum: The amount by which the angle is changed just below.
310
     */
311
    for (axis=PITCH; axis<=ROLL; axis++) {
312
      accDerived = getAngleEstimateFromAcc(axis);
313
      DebugOut.Analog[9 + axis] = (10 * accDerived) / GYRO_DEG_FACTOR_PITCHROLL;
314
      DebugOut.Analog[18 + axis] = getAngleEstimateFromAcc(axis);
315
 
316
      // 1000 * the correction amount that will be added to the gyro angle in next line.
317
      correction = angle[axis]; //(permilleAcc * (accDerived - angle[axis])) / 1000;
318
      angle[axis] = ((int32_t)(1000L - permilleAcc) * angle[axis] + (int32_t)permilleAcc * accDerived) / 1000L;
319
 
320
      correctionSum[axis] += angle[axis] - correction;
321
 
322
      DebugOut.Analog[14+axis] = permilleAcc;
323
      DebugOut.Analog[16+axis] = angle[axis] - correction;
324
    }
325
 
326
    // DebugOut.Digital[1] |= DEBUG_ACC0THORDER;
327
  } else {
328
    DebugOut.Digital[0] &= ~DEBUG_ACC0THORDER;
329
  }
330
}
331
 
332
/************************************************************************
333
 * This is an attempt to correct not the error in the angle integrals
334
 * (that happens in correctIntegralsByAcc0thOrder above) but rather the
335
 * cause of it: Gyro drift, vibration and rounding errors.
336
 * All the corrections made in correctIntegralsByAcc0thOrder over
337
 * DRIFTCORRECTION_TIME cycles are summed up. This number is
338
 * then divided by DRIFTCORRECTION_TIME to get the approx.
339
 * correction that should have been applied to each iteration to fix
340
 * the error. This is then added to the dynamic offsets.
341
 ************************************************************************/
342
// 2 times / sec. = 488/2
343
#define DRIFTCORRECTION_TIME 256L
344
void driftCorrection(void) {
345
  static int16_t timer = DRIFTCORRECTION_TIME;
346
  int16_t deltaCorrection;
347
  uint8_t axis;
348
  if (! --timer) {
349
    timer = DRIFTCORRECTION_TIME;
350
    for (axis=PITCH; axis<=ROLL; axis++) {
351
      // Take the sum of corrections applied, add it to delta
352
      deltaCorrection = ((correctionSum[axis] + DRIFTCORRECTION_TIME / 2) * HIRES_GYRO_INTEGRATION_FACTOR) / DRIFTCORRECTION_TIME;
353
      // Add the delta to the compensation. So positive delta means, gyro should have higher value.
354
      driftComp[axis] += deltaCorrection / staticParams.GyroAccTrim;
355
      CHECK_MIN_MAX(driftComp[axis], -staticParams.DriftComp, staticParams.DriftComp);
356
      // DebugOut.Analog[11 + axis] = correctionSum[axis];
357
      DebugOut.Analog[28 + axis] = driftComp[axis];
358
      correctionSum[axis] = 0;
359
    }
360
  }
361
}
362
 
363
/************************************************************************
364
 * Main procedure.
365
 ************************************************************************/
366
void calculateFlightAttitude(void) {  
367
  // part1: 550 usec.
368
  // part1a: 550 usec.
369
  // part1b: 60 usec.
370
  getAnalogData();
371
  // end part1b
372
  integrate();
373
  // end part1a
374
 
375
 
376
  DebugOut.Analog[6] = ACRate[PITCH];
377
  DebugOut.Analog[7] = ACRate[ROLL];
378
  DebugOut.Analog[8] = ACYawRate;
379
 
380
  DebugOut.Analog[3] = rate_PID[PITCH];
381
  DebugOut.Analog[4] = rate_PID[ROLL];
382
  DebugOut.Analog[5] = yawRate;
383
 
384
#ifdef ATTITUDE_USE_ACC_SENSORS
385
  correctIntegralsByAcc0thOrder();
386
  driftCorrection();
387
#endif
388
  // end part1
389
}
390
 
391
void updateCompass(void) {
392
  int16_t w, v, r,correction, error;
393
 
394
  if(compassCalState && !(MKFlags & MKFLAG_MOTOR_RUN)) {
395
    if (controlMixer_testCompassCalState()) {
396
      compassCalState++;
397
      if(compassCalState < 5) beepNumber(compassCalState);
398
      else beep(1000);
399
    }
400
  } else {
401
    // get maximum attitude angle
402
    w = abs(angle[PITCH] / 512);
403
    v = abs(angle[ROLL]  / 512);
404
    if(v > w) w = v;
405
    correction = w / 8 + 1;
406
    // calculate the deviation of the yaw gyro heading and the compass heading
407
    if (compassHeading < 0) error = 0; // disable yaw drift compensation if compass heading is undefined
408
    else error = ((540 + compassHeading - (yawGyroHeading / GYRO_DEG_FACTOR_YAW)) % 360) - 180;
409
    if(abs(yawRate) > 128) { // spinning fast
410
      error = 0;
411
    }
412
    if(!badCompassHeading && w < 25) {
413
      yawGyroDrift += error;
414
      if(updateCompassCourse) {
415
        beep(200);
416
        yawGyroHeading = (int32_t)compassHeading * GYRO_DEG_FACTOR_YAW;
417
        compassCourse = compassHeading; //(int16_t)(yawGyroHeading / GYRO_DEG_FACTOR_YAW);
418
        updateCompassCourse = 0;
419
      }
420
    }
421
    yawGyroHeading += (error * 8) / correction;
422
    w = (w * dynamicParams.CompassYawEffect) / 32;
423
    w = dynamicParams.CompassYawEffect - w;
424
    if(w >= 0) {
425
      if(!badCompassHeading) {
426
        v = 64 + (maxControl[PITCH] + maxControl[ROLL]) / 8;
427
        // calc course deviation
428
        r = ((540 + (yawGyroHeading / GYRO_DEG_FACTOR_YAW) - compassCourse) % 360) - 180;
429
        v = (r * w) / v; // align to compass course
430
        // limit yaw rate
431
        w = 3 * dynamicParams.CompassYawEffect;
432
        if (v > w) v = w;
433
        else if (v < -w) v = -w;
434
        yawAngleDiff += v;
435
      }
436
      else
437
        { // wait a while
438
          badCompassHeading--;
439
        }
440
    } else {  // ignore compass at extreme attitudes for a while
441
      badCompassHeading = 500;
442
    }
443
  }
444
}
445
 
446
/*
447
 * This is part of an experiment to measure average sensor offsets caused by motor vibration,
448
 * and to compensate them away. It brings about some improvement, but no miracles.
449
 * As long as the left stick is kept in the start-motors position, the dynamic compensation
450
 * will measure the effect of vibration, to use for later compensation. So, one should keep
451
 * the stick in the start-motors position for a few seconds, till all motors run (at the wrong
452
 * speed unfortunately... must find a better way)
453
 */
454
/*
455
  void attitude_startDynamicCalibration(void) {
456
  dynamicCalPitch = dynamicCalRoll = dynamicCalYaw = dynamicCalCount = 0;
457
  savedDynamicOffsetPitch = savedDynamicOffsetRoll = 1000;
458
  }
459
 
460
  void attitude_continueDynamicCalibration(void) {
461
  // measure dynamic offset now...
462
  dynamicCalPitch += hiResPitchGyro;
463
  dynamicCalRoll += hiResRollGyro;
464
  dynamicCalYaw += rawYawGyroSum;
465
  dynamicCalCount++;
466
 
467
  // Param6: Manual mode. The offsets are taken from Param7 and Param8.
468
  if (dynamicParams.UserParam6 || 1) { // currently always enabled.
469
  // manual mode
470
  driftCompPitch = dynamicParams.UserParam7 - 128;
471
  driftCompRoll = dynamicParams.UserParam8 - 128;
472
  } else {
473
  // use the sampled value (does not seem to work so well....)
474
  driftCompPitch = savedDynamicOffsetPitch = -dynamicCalPitch / dynamicCalCount;
475
  driftCompRoll = savedDynamicOffsetRoll = -dynamicCalRoll / dynamicCalCount;
476
  driftCompYaw = -dynamicCalYaw / dynamicCalCount;
477
  }
478
 
479
  // keep resetting these meanwhile, to avoid accumulating errors.
480
  setStaticAttitudeIntegrals();
481
  yawAngle = 0;
482
  }
483
*/